├── .github
├── badges
│ ├── jacoco.svg
│ └── udemy.svg
└── workflows
│ ├── gradle.yml
│ ├── lint.yml
│ └── udemy.yml
├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── jarRepositories.xml
├── misc.xml
├── runConfigurations
│ ├── All_in_grpc_java_course_test.xml
│ ├── BlogClient.xml
│ ├── BlogDb.xml
│ ├── BlogServer.xml
│ ├── CalculatorClient_avg.xml
│ ├── CalculatorClient_max.xml
│ ├── CalculatorClient_primes.xml
│ ├── CalculatorClient_sqrt.xml
│ ├── CalculatorClient_sum.xml
│ ├── CalculatorServer.xml
│ ├── GreetingClientTls.xml
│ ├── GreetingClient_greet.xml
│ ├── GreetingClient_greet_everyone.xml
│ ├── GreetingClient_greet_many_times.xml
│ ├── GreetingClient_greet_with_deadline.xml
│ ├── GreetingClient_long_greet.xml
│ ├── GreetingServer.xml
│ └── GreetingServerTls.xml
└── vcs.xml
├── .protolint
└── .protolint.yaml
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
├── src
├── main
│ ├── java
│ │ ├── blog
│ │ │ ├── client
│ │ │ │ └── BlogClient.java
│ │ │ ├── docker-compose.yml
│ │ │ └── server
│ │ │ │ ├── BlogServer.java
│ │ │ │ └── BlogServiceImpl.java
│ │ ├── calculator
│ │ │ ├── client
│ │ │ │ └── CalculatorClient.java
│ │ │ └── server
│ │ │ │ ├── CalculatorServer.java
│ │ │ │ └── CalculatorServiceImpl.java
│ │ ├── greeting
│ │ │ ├── client
│ │ │ │ ├── AddHeaderInterceptor.java
│ │ │ │ ├── GreetingClient.java
│ │ │ │ ├── GreetingClientTls.java
│ │ │ │ └── LogInterceptor.java
│ │ │ └── server
│ │ │ │ ├── GreetingServer.java
│ │ │ │ ├── GreetingServerTls.java
│ │ │ │ ├── GreetingServiceImpl.java
│ │ │ │ ├── HeaderCheckInterceptor.java
│ │ │ │ ├── LogInterceptor.java
│ │ │ │ └── SleeperImpl.java
│ │ └── utils
│ │ │ ├── ExcludeFromJacocoGeneratedReport.java
│ │ │ └── Sleeper.java
│ └── proto
│ │ ├── blog
│ │ └── blog.proto
│ │ ├── calculator
│ │ ├── avg.proto
│ │ ├── calculator.proto
│ │ ├── max.proto
│ │ ├── prime.proto
│ │ ├── sqrt.proto
│ │ └── sum.proto
│ │ ├── dummy.proto
│ │ └── greeting
│ │ └── greeting.proto
└── test
│ └── java
│ ├── blog
│ ├── client
│ │ ├── BlogCreateTest.java
│ │ ├── BlogDeleteTest.java
│ │ ├── BlogListTest.java
│ │ ├── BlogReadTest.java
│ │ └── BlogUpdateTest.java
│ └── server
│ │ ├── BlogCreateTest.java
│ │ ├── BlogDeleteTest.java
│ │ ├── BlogListTest.java
│ │ ├── BlogReadTest.java
│ │ └── BlogUpdateTest.java
│ ├── calculator
│ └── server
│ │ ├── CalculatorAvgTest.java
│ │ ├── CalculatorMaxTest.java
│ │ ├── CalculatorPrimesTest.java
│ │ ├── CalculatorSqrtTest.java
│ │ └── CalculatorSumTest.java
│ ├── greeting
│ └── server
│ │ ├── GreetingEveryoneServerTest.java
│ │ ├── GreetingManyTimesServerTest.java
│ │ ├── GreetingServerTest.java
│ │ ├── GreetingWithDeadlineTest.java
│ │ ├── GreetingWithDeadlineThrowsTest.java
│ │ ├── InterceptorTest.java
│ │ └── LongGreetingServerTest.java
│ └── utils
│ ├── ClientTestBase.java
│ ├── ServerTestBase.java
│ └── StubInstantiator.java
└── ssl
├── README.md
└── ssl.sh
/.github/badges/jacoco.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/badges/udemy.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | name: build master branch
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | paths:
7 | - "src/**/*.java"
8 | - "*.gradle"
9 | - "gradle-*"
10 | pull_request:
11 | branches: [ master ]
12 | paths:
13 | - "src/**/*.java"
14 | - "*.gradle"
15 | - "gradle-*"
16 |
17 | jobs:
18 | build:
19 | runs-on: ${{ matrix.os }}
20 |
21 | strategy:
22 | matrix:
23 | os: [windows-2022, ubuntu-20.04, macos-11]
24 | jdk: ['8', '17']
25 | steps:
26 | - uses: actions/checkout@v2
27 | - name: Set up JDK
28 | uses: actions/setup-java@v2
29 | with:
30 | java-version: ${{ matrix.jdk }}
31 | distribution: 'temurin'
32 | cache: gradle
33 |
34 | - name: Build with Gradle
35 | uses: gradle/gradle-build-action@937999e9cc2425eddc7fd62d1053baf041147db7
36 | with:
37 | arguments: build -x test --no-daemon
38 |
39 | codecov:
40 |
41 | runs-on: ubuntu-latest
42 | needs: build
43 | steps:
44 | - uses: actions/checkout@v2
45 | - name: Run Test Coverage
46 | run: ./gradlew jacocoTestReport
47 |
48 | - name: Generate JaCoCo Badge
49 | uses: cicirello/jacoco-badge-generator@v2
50 | with:
51 | jacoco-csv-file: build/reports/jacoco/jacoco.csv
52 |
53 | - name: Commit the badge (if it changed)
54 | run: |
55 | if [[ `git status --porcelain` ]]; then
56 | git config --global user.name 'Clement Jean'
57 | git config --global user.email 'Clement-Jean@users.noreply.github.com'
58 | git add .github/badges/jacoco.svg
59 | git commit -m "Autogenerated JaCoCo coverage badge"
60 | git push
61 | fi
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: lint protocol buffers
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | paths:
7 | - "src/**/*.proto"
8 | pull_request:
9 | branches: [ master ]
10 | paths:
11 | - "src/**/*.proto"
12 |
13 | jobs:
14 | pr-check:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - name: Checkout source
18 | uses: actions/checkout@v1
19 |
20 | - name: Run protolint
21 | uses: plexsystems/protolint-action@v0.4.0
22 | with:
23 | configDirectory: .protolint
--------------------------------------------------------------------------------
/.github/workflows/udemy.yml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_dispatch:
3 | schedule:
4 | - cron: '0 0 1 * *'
5 |
6 | jobs:
7 | generate_badge:
8 | runs-on: ubuntu-latest
9 | name: badge_generation
10 | steps:
11 | - name: Checkout
12 | uses: actions/checkout@v2
13 | - name: Badge generation
14 | uses: Clement-Jean/udemy-badge-generator@v1
15 | env:
16 | UDEMY_TOKEN: ${{ secrets.UDEMY_TOKEN }}
17 | UDEMY_COURSE: ${{ secrets.UDEMY_COURSE }}
18 | - name: Commit the badge (if it changed)
19 | run: |
20 | if [[ `git status --porcelain` ]]; then
21 | git config --global user.name 'Clement Jean'
22 | git config --global user.email 'Clement-Jean@users.noreply.github.com'
23 | git add .github/badges/udemy.svg
24 | git commit -m "Autogenerated Udemy rating badge"
25 | git push
26 | fi
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## IDEA IntelliJ
2 |
3 | # User-specific stuff
4 | .idea/**/workspace.xml
5 | .idea/**/tasks.xml
6 | .idea/**/usage.statistics.xml
7 | .idea/**/dictionaries
8 | .idea/**/shelf
9 |
10 | # Generated files
11 | .idea/**/contentModel.xml
12 |
13 | # Sensitive or high-churn files
14 | .idea/**/dataSources/
15 | .idea/**/dataSources.ids
16 | .idea/**/dataSources.local.xml
17 | .idea/**/sqlDataSources.xml
18 | .idea/**/dynamic.xml
19 | .idea/**/uiDesigner.xml
20 | .idea/**/dbnavigator.xml
21 |
22 | # Gradle
23 | .idea/**/gradle.xml
24 | .idea/**/libraries
25 |
26 | # File-based project format
27 | *.iws
28 |
29 | # IntelliJ
30 | out/
31 |
32 | ## JAVA
33 |
34 | # Compiled class file
35 | *.class
36 |
37 | # Log file
38 | *.log
39 |
40 | # Package Files #
41 | *.jar
42 | *.war
43 | *.nar
44 | *.ear
45 | *.zip
46 | *.tar.gz
47 | *.rar
48 |
49 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
50 | hs_err_pid*
51 | replay_pid*
52 |
53 |
54 | ## Gradle
55 |
56 | .gradle
57 | **/build/
58 | !src/**/build/
59 |
60 | # Ignore Gradle GUI config
61 | gradle-app.setting
62 |
63 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
64 | !gradle-wrapper.jar
65 |
66 | # Cache of project
67 | .gradletasknamecache
68 |
69 | # Eclipse Gradle plugin generated files
70 | # Eclipse Core
71 | .project
72 | # JDT-specific (Eclipse Java Development Tools)
73 | .classpath
74 |
75 |
76 | ## SSL
77 | *.crt
78 | *.key
79 | *.csr
80 | *.pem
81 |
82 | ## Mac
83 | .DS_Store
84 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
25 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/All_in_grpc_java_course_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/BlogClient.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/BlogDb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/BlogServer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/CalculatorClient_avg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/CalculatorClient_max.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/CalculatorClient_primes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/CalculatorClient_sqrt.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/CalculatorClient_sum.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/CalculatorServer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/GreetingClientTls.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/GreetingClient_greet.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/GreetingClient_greet_everyone.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/GreetingClient_greet_many_times.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/GreetingClient_greet_with_deadline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/GreetingClient_long_greet.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/GreetingServer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/GreetingServerTls.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.protolint/.protolint.yaml:
--------------------------------------------------------------------------------
1 | lint:
2 | directories:
3 | exclude:
4 | - build
5 | rules:
6 | no_default: false
7 | add:
8 | - ENUM_FIELD_NAMES_PREFIX
9 | - ENUM_FIELD_NAMES_UPPER_SNAKE_CASE
10 | - ENUM_FIELD_NAMES_ZERO_VALUE_END_WITH
11 | - ENUM_NAMES_UPPER_CAMEL_CASE
12 | - FILE_NAMES_LOWER_SNAKE_CASE
13 | - FIELD_NAMES_LOWER_SNAKE_CASE
14 | - MPORTS_SORTED
15 | - MESSAGE_NAMES_UPPER_CAMEL_CASE
16 | - ORDER
17 | - PACKAGE_NAME_LOWER_CASE
18 | - RPC_NAMES_UPPER_CAMEL_CASE
19 | - SERVICE_NAMES_UPPER_CAMEL_CASE
20 | - REPEATED_FIELD_NAMES_PLURALIZED
21 | - QUOTE_CONSISTENT
22 | - INDENT
23 | - PROTO3_FIELDS_AVOID_REQUIRED
24 | - PROTO3_GROUPS_AVOID
25 | - MAX_LINE_LENGTH
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # gRPC Java
2 |
3 | [](https://github.com/Clement-Jean/grpc-java-course/actions/workflows/gradle.yml)  [](https://github.com/Clement-Jean/grpc-java-course/actions/workflows/lint.yml) 
4 |
5 | ## COUPON: `START_OCT_2025`
6 |
7 | ## Notes
8 |
9 | - The code you see in this repository might be little different from what you saw in the course videos, this is due to the fact that:
10 | - I'm testing the code
11 | - I or a student noticed an error/bug/deprecation after recording
12 | - Dependencies are evolving faster than I can rerecord
13 |
14 | I do the maximum to keep the main features and the code syntax similar by keeping the edits trivial. **However if you
15 | do get in a situation where you feel lost, leave an `issue` on the repository**
16 | - The coverage shown in the badges section only counts the classes that need testing, such as:
17 | - greeting/server/GreetingServiceImpl
18 | - calculator/server/CalculatorServiceImpl
19 | - blog/server/BlogServiceImpl
20 | - blog/client/BlogClient
21 |
22 | For more information, please check the `jacocoTestReport` task in `build.gradle`
23 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | //file:noinspection GrUnresolvedAccess
2 | //file:noinspection GroovyAssignabilityCheck
3 | plugins {
4 | id 'java'
5 | id 'idea'
6 | id 'com.google.protobuf' version '0.9.4'
7 |
8 | id 'jacoco'
9 | }
10 |
11 | group 'com.clementjean.grpc'
12 | version '1.0-SNAPSHOT'
13 |
14 | repositories {
15 | mavenCentral()
16 | }
17 |
18 | ext {
19 | protoVersion = '3.24.4'
20 | grpcVersion = '1.59.0'
21 | }
22 |
23 | protobuf {
24 | protoc {
25 | artifact = "com.google.protobuf:protoc:$protoVersion"
26 | }
27 | plugins {
28 | grpc {
29 | artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion"
30 | }
31 | }
32 | generateProtoTasks {
33 | all()*.plugins {
34 | grpc {}
35 | }
36 | }
37 | }
38 |
39 | sourceSets.main.java.srcDir new File(buildDir, 'generated/source')
40 |
41 | dependencies {
42 | runtimeOnly "io.grpc:grpc-netty-shaded:$grpcVersion"
43 | implementation "io.grpc:grpc-protobuf:$grpcVersion"
44 | implementation "io.grpc:grpc-stub:$grpcVersion"
45 | implementation "io.grpc:grpc-services:$grpcVersion"
46 | compileOnly 'org.apache.tomcat:annotations-api:6.0.53'
47 | implementation "com.google.protobuf:protobuf-java-util:$protoVersion"
48 |
49 | implementation 'org.mongodb:mongodb-driver-sync:4.11.0'
50 |
51 | testImplementation 'junit:junit:4.13.2'
52 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2'
53 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2'
54 | testImplementation 'org.mockito:mockito-core:5.2.0'
55 | testImplementation "io.grpc:grpc-inprocess:$grpcVersion"
56 | }
57 |
58 | test {
59 | useJUnitPlatform()
60 | finalizedBy jacocoTestReport
61 | }
62 |
63 | jacocoTestReport {
64 | dependsOn test
65 |
66 | reports {
67 | xml.required = false
68 | html.required = false
69 | csv.required = true
70 | csv.destination file("${buildDir}/reports/jacoco/jacoco.csv")
71 | }
72 | afterEvaluate {
73 | classDirectories.setFrom(files(classDirectories.files.collect {
74 | fileTree(
75 | dir: it,
76 | includes: [
77 | "greeting/server/GreetingServiceImpl.class",
78 | "calculator/server/CalculatorServiceImpl.class",
79 | "blog/server/BlogServiceImpl.class",
80 | "blog/client/BlogClient.class",
81 | ]
82 | )
83 | }))
84 | }
85 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Clement-Jean/grpc-java-course/e4c7e468d394ab7f06829098c3ca81169e9b0ccc/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-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MSYS* | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/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 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'grpc-java-course'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/blog/client/BlogClient.java:
--------------------------------------------------------------------------------
1 | package blog.client;
2 |
3 | import com.google.common.annotations.VisibleForTesting;
4 | import com.google.protobuf.Empty;
5 | import com.proto.blog.Blog;
6 | import com.proto.blog.BlogId;
7 | import com.proto.blog.BlogServiceGrpc;
8 | import io.grpc.ManagedChannel;
9 | import io.grpc.ManagedChannelBuilder;
10 | import io.grpc.StatusRuntimeException;
11 | import utils.ExcludeFromJacocoGeneratedReport;
12 |
13 | import javax.annotation.Nonnull;
14 | import javax.annotation.Nullable;
15 | import java.io.PrintStream;
16 |
17 | public final class BlogClient {
18 |
19 | private BlogClient() {}
20 |
21 | @Nullable
22 | @VisibleForTesting
23 | static BlogId createBlog(BlogServiceGrpc.BlogServiceBlockingStub stub) {
24 | System.out.println("Creating blog....");
25 |
26 | try {
27 | BlogId createResponse = stub.createBlog(
28 | Blog.newBuilder()
29 | .setAuthor("Clement")
30 | .setTitle("New blog!")
31 | .setContent("Hello world this is my first blog!")
32 | .build()
33 | );
34 |
35 | System.out.println("Blog created: " + createResponse.getId());
36 | System.out.println();
37 | return createResponse;
38 | } catch (StatusRuntimeException e) {
39 | System.out.println("Couldn't create the blog");
40 | e.printStackTrace();
41 | return null;
42 | }
43 | }
44 |
45 | @Nullable
46 | @VisibleForTesting
47 | static Blog readBlog(BlogServiceGrpc.BlogServiceBlockingStub stub, @Nonnull BlogId blogId) {
48 | System.out.println("Reading blog....");
49 |
50 | try {
51 | Blog readResponse = stub.readBlog(blogId);
52 |
53 | System.out.println("Blog read:" + readResponse);
54 | return readResponse;
55 | } catch (StatusRuntimeException e) {
56 | System.out.println("Couldn't read the blog");
57 | e.printStackTrace();
58 | return null;
59 | }
60 | }
61 |
62 | @Nullable
63 | @VisibleForTesting
64 | @SuppressWarnings("ResultOfMethodCallIgnored")
65 | static Blog updateBlog(BlogServiceGrpc.BlogServiceBlockingStub stub, @Nonnull BlogId blogId) {
66 | try {
67 | Blog newBlog = Blog.newBuilder()
68 | .setId(blogId.getId())
69 | .setAuthor("Changed Author")
70 | .setTitle("New blog (updated)!")
71 | .setContent("Hello world this is my first blog! I've added some more content")
72 | .build();
73 |
74 | System.out.println("Updating blog...");
75 | stub.updateBlog(newBlog);
76 |
77 | System.out.println("Blog updated:");
78 | System.out.println(newBlog);
79 | return newBlog;
80 | } catch (StatusRuntimeException e) {
81 | System.out.println("Couldn't update the blog");
82 | e.printStackTrace();
83 | return null;
84 | }
85 | }
86 |
87 | @VisibleForTesting
88 | static void listBlogs(BlogServiceGrpc.BlogServiceBlockingStub stub, PrintStream ps) {
89 | ps.println("Listing blogs...");
90 | stub.listBlogs(Empty.getDefaultInstance()).forEachRemaining(ps::print);
91 | }
92 |
93 | @Nullable
94 | @VisibleForTesting
95 | @SuppressWarnings("ResultOfMethodCallIgnored")
96 | static BlogId deleteBlog(BlogServiceGrpc.BlogServiceBlockingStub stub, @Nonnull BlogId blogId) {
97 | try {
98 | System.out.println("Deleting blog");
99 | stub.deleteBlog(blogId);
100 |
101 | System.out.println("Blog deleted: " + blogId.getId());
102 | return blogId;
103 | } catch (StatusRuntimeException e) {
104 | System.out.println("Couldn't delete the blog");
105 | e.printStackTrace();
106 | return null;
107 | }
108 | }
109 |
110 | @ExcludeFromJacocoGeneratedReport
111 | private static void run(ManagedChannel channel) {
112 | BlogServiceGrpc.BlogServiceBlockingStub stub = BlogServiceGrpc.newBlockingStub(channel);
113 |
114 | BlogId id = createBlog(stub);
115 |
116 | if (id == null)
117 | return;
118 |
119 | readBlog(stub, id);
120 | updateBlog(stub, id);
121 | listBlogs(stub, System.out);
122 | deleteBlog(stub, id);
123 | }
124 |
125 | @ExcludeFromJacocoGeneratedReport
126 | public static void main(String[] args) {
127 | ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051)
128 | .usePlaintext()
129 | .build();
130 |
131 | run(channel);
132 |
133 | System.out.println("Shutting Down");
134 | channel.shutdown();
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/main/java/blog/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.1'
2 |
3 | services:
4 | mongo:
5 | image: mongo
6 | restart: always
7 | ports:
8 | - "27017:27017"
9 | environment:
10 | MONGO_INITDB_ROOT_USERNAME: root
11 | MONGO_INITDB_ROOT_PASSWORD: root
12 |
13 | mongo-express:
14 | image: mongo-express
15 | restart: always
16 | ports:
17 | - "8081:8081"
18 | environment:
19 | ME_CONFIG_MONGODB_ADMINUSERNAME: root
20 | ME_CONFIG_MONGODB_ADMINPASSWORD: root
21 | ME_CONFIG_MONGODB_URL: mongodb://root:root@mongo:27017/
--------------------------------------------------------------------------------
/src/main/java/blog/server/BlogServer.java:
--------------------------------------------------------------------------------
1 | package blog.server;
2 |
3 | import com.mongodb.client.MongoClient;
4 | import com.mongodb.client.MongoClients;
5 | import io.grpc.Server;
6 | import io.grpc.ServerBuilder;
7 |
8 | import java.io.IOException;
9 |
10 | public final class BlogServer {
11 | public static void main(String[] args) throws InterruptedException, IOException {
12 | int port = 50051;
13 |
14 | MongoClient client = MongoClients.create("mongodb://root:root@localhost:27017/");
15 |
16 | Server server = ServerBuilder.forPort(port)
17 | .addService(new BlogServiceImpl(client))
18 | .build();
19 |
20 | server.start();
21 | System.out.println("Server Started");
22 | System.out.println("Listening on port: " + port);
23 |
24 | Runtime.getRuntime().addShutdownHook(new Thread(() -> {
25 | System.out.println("Received Shutdown Request");
26 | server.shutdown();
27 | client.close();
28 | System.out.println("Server Stopped");
29 | }));
30 |
31 | server.awaitTermination();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/blog/server/BlogServiceImpl.java:
--------------------------------------------------------------------------------
1 | package blog.server;
2 |
3 | import com.google.common.annotations.VisibleForTesting;
4 | import com.google.protobuf.Empty;
5 | import com.mongodb.MongoException;
6 | import com.mongodb.client.*;
7 | import com.mongodb.client.result.DeleteResult;
8 | import com.mongodb.client.result.InsertOneResult;
9 | import com.proto.blog.Blog;
10 | import com.proto.blog.BlogId;
11 | import com.proto.blog.BlogServiceGrpc;
12 | import io.grpc.Status;
13 | import io.grpc.stub.StreamObserver;
14 | import org.bson.Document;
15 | import org.bson.types.ObjectId;
16 |
17 | import static com.mongodb.client.model.Filters.eq;
18 | import static com.mongodb.client.model.Updates.combine;
19 | import static com.mongodb.client.model.Updates.set;
20 |
21 | public final class BlogServiceImpl extends BlogServiceGrpc.BlogServiceImplBase {
22 |
23 | @VisibleForTesting
24 | static final String BLOG_COULDNT_BE_CREATED = "The blog could not be created";
25 | @VisibleForTesting
26 | static final String BLOG_COULDNT_BE_DELETED = "The blog could not be deleted";
27 | @VisibleForTesting
28 | static final String BLOG_WAS_NOT_FOUND = "The blog with the corresponding id was not found";
29 | @VisibleForTesting
30 | static final String ID_CANNOT_BE_EMPTY = "The blog ID cannot be empty";
31 |
32 | private final MongoCollection mongoCollection;
33 |
34 | BlogServiceImpl(MongoClient client) {
35 | MongoDatabase db = client.getDatabase("blogdb");
36 | mongoCollection = db.getCollection("blog");
37 | }
38 |
39 | private io.grpc.StatusRuntimeException error(Status status, String message) {
40 | return status.withDescription(message).asRuntimeException();
41 | }
42 |
43 | @SuppressWarnings("SameParameterValue")
44 | private io.grpc.StatusRuntimeException error(Status status, String message, String augmentMessage) {
45 | return status.withDescription(message)
46 | .augmentDescription(augmentMessage)
47 | .asRuntimeException();
48 | }
49 |
50 | Blog documentToBlog(Document document) {
51 | return Blog.newBuilder()
52 | .setAuthor(document.getString("author"))
53 | .setTitle(document.getString("title"))
54 | .setContent(document.getString("content"))
55 | .setId(document.getObjectId("_id").toString())
56 | .build();
57 | }
58 |
59 | @Override
60 | public void createBlog(Blog request, StreamObserver responseObserver) {
61 | System.out.println("Received Create Blog request");
62 |
63 | Document doc = new Document("author", request.getAuthor())
64 | .append("title", request.getTitle())
65 | .append("content", request.getContent());
66 |
67 | System.out.println("Inserting blog...");
68 | InsertOneResult result;
69 |
70 | try {
71 | result = mongoCollection.insertOne(doc);
72 | } catch (MongoException e) {
73 | responseObserver.onError(error(Status.INTERNAL, BLOG_COULDNT_BE_CREATED, e.getLocalizedMessage()));
74 | return;
75 | }
76 |
77 | if (!result.wasAcknowledged() || result.getInsertedId() == null) {
78 | responseObserver.onError(error(Status.INTERNAL, BLOG_COULDNT_BE_CREATED));
79 | return;
80 | }
81 |
82 | String id = result.getInsertedId().asObjectId().getValue().toString();
83 | System.out.println("Inserted blog: " + id);
84 |
85 | responseObserver.onNext(BlogId.newBuilder().setId(id).build());
86 | responseObserver.onCompleted();
87 | }
88 |
89 | @Override
90 | public void readBlog(BlogId request, StreamObserver responseObserver) {
91 | System.out.println("Received Read Blog request");
92 |
93 | if (request.getId().isEmpty()) {
94 | responseObserver.onError(error(Status.INVALID_ARGUMENT, ID_CANNOT_BE_EMPTY));
95 | return;
96 | }
97 |
98 | String id = request.getId();
99 |
100 | System.out.println("Searching for a blog with id: " + id);
101 | Document result = mongoCollection.find(eq("_id", new ObjectId(id))).first();
102 |
103 | if (result == null) {
104 | System.out.println("Blog not found");
105 | responseObserver.onError(
106 | error(
107 | Status.NOT_FOUND,
108 | BLOG_WAS_NOT_FOUND,
109 | "BlogId: " + id
110 | )
111 | );
112 | return;
113 | }
114 |
115 | System.out.println("Blog found, sending response");
116 | responseObserver.onNext(documentToBlog(result));
117 | responseObserver.onCompleted();
118 | }
119 |
120 | @Override
121 | public void updateBlog(Blog request, StreamObserver responseObserver) {
122 | System.out.println("Received Update Blog request");
123 |
124 | if (request.getId().isEmpty()) {
125 | responseObserver.onError(error(Status.INVALID_ARGUMENT, ID_CANNOT_BE_EMPTY));
126 | return;
127 | }
128 |
129 | String id = request.getId();
130 |
131 | System.out.println("Searching for a blog so we can update it");
132 | Document result = mongoCollection.findOneAndUpdate(
133 | eq("_id", new ObjectId(id)),
134 | combine(
135 | set("author", request.getAuthor()),
136 | set("title", request.getTitle()),
137 | set("content", request.getContent())
138 | )
139 | );
140 |
141 | if (result == null) {
142 | System.out.println("Blog not found");
143 | responseObserver.onError(
144 | error(
145 | Status.NOT_FOUND,
146 | BLOG_WAS_NOT_FOUND,
147 | "BlogId: " + id
148 | )
149 | );
150 | return;
151 | }
152 |
153 | System.out.println("Replaced! Sending as a response");
154 | responseObserver.onNext(Empty.getDefaultInstance());
155 | responseObserver.onCompleted();
156 | }
157 |
158 | @Override
159 | public void deleteBlog(BlogId request, StreamObserver responseObserver) {
160 | System.out.println("Received Delete Blog Request");
161 |
162 | if (request.getId().isEmpty()) {
163 | responseObserver.onError(error(Status.INVALID_ARGUMENT, ID_CANNOT_BE_EMPTY));
164 | return;
165 | }
166 |
167 | String id = request.getId();
168 | DeleteResult result;
169 |
170 | try {
171 | result = mongoCollection.deleteOne(eq("_id", new ObjectId(id)));
172 | } catch (MongoException e) {
173 | responseObserver.onError(error(Status.INTERNAL, BLOG_COULDNT_BE_DELETED, e.getLocalizedMessage()));
174 | return;
175 | }
176 |
177 | if (!result.wasAcknowledged()) {
178 | System.out.println("Blog could not be deleted");
179 | responseObserver.onError(error(Status.INTERNAL, BLOG_COULDNT_BE_DELETED));
180 | return;
181 | }
182 |
183 | if (result.getDeletedCount() == 0) {
184 | System.out.println("Blog not found");
185 | responseObserver.onError(
186 | error(
187 | Status.NOT_FOUND,
188 | BLOG_WAS_NOT_FOUND,
189 | "BlogId: " + id
190 | )
191 | );
192 | return;
193 | }
194 |
195 | System.out.println("Blog was deleted");
196 | responseObserver.onNext(Empty.getDefaultInstance());
197 | responseObserver.onCompleted();
198 | }
199 |
200 | @Override
201 | public void listBlogs(Empty request, StreamObserver responseObserver) {
202 | System.out.println("Received List Blog Request");
203 |
204 | for (Document document : mongoCollection.find()) {
205 | responseObserver.onNext(documentToBlog(document));
206 | }
207 |
208 | responseObserver.onCompleted();
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/src/main/java/calculator/client/CalculatorClient.java:
--------------------------------------------------------------------------------
1 | package calculator.client;
2 |
3 | import com.proto.calculator.*;
4 | import io.grpc.ManagedChannel;
5 | import io.grpc.ManagedChannelBuilder;
6 | import io.grpc.stub.StreamObserver;
7 |
8 | import java.util.Arrays;
9 | import java.util.concurrent.CountDownLatch;
10 | import java.util.concurrent.TimeUnit;
11 | import java.util.stream.IntStream;
12 |
13 | public final class CalculatorClient {
14 | private static void doSum(ManagedChannel channel) {
15 | System.out.println("Enter doSum");
16 | CalculatorServiceGrpc.CalculatorServiceBlockingStub stub = CalculatorServiceGrpc.newBlockingStub(channel);
17 | SumResponse response = stub.sum(SumRequest.newBuilder().setFirstNumber(1).setSecondNumber(1).build());
18 |
19 | System.out.println("Sum 1 + 1 = " + response.getResult());
20 | }
21 |
22 | private static void doPrimes(ManagedChannel channel) {
23 | System.out.println("Enter doPrimes");
24 | CalculatorServiceGrpc.CalculatorServiceBlockingStub stub = CalculatorServiceGrpc.newBlockingStub(channel);
25 |
26 | stub.primes(PrimeRequest.newBuilder().setNumber(567890).build()).forEachRemaining(response ->
27 | System.out.println(response.getPrimeFactor())
28 | );
29 | }
30 |
31 | private static void doAvg(ManagedChannel channel) throws InterruptedException {
32 | System.out.println("Enter doAvg");
33 | CalculatorServiceGrpc.CalculatorServiceStub stub = CalculatorServiceGrpc.newStub(channel);
34 | CountDownLatch latch = new CountDownLatch(1);
35 |
36 | StreamObserver stream = stub.avg(new StreamObserver() {
37 | @Override
38 | public void onNext(AvgResponse response) {
39 | System.out.println("Avg = " + response.getResult());
40 | }
41 |
42 | @Override
43 | public void onError(Throwable t) {}
44 |
45 | @Override
46 | public void onCompleted() {
47 | latch.countDown();
48 | }
49 | });
50 |
51 | IntStream.range(1, 11).forEach(number ->
52 | stream.onNext(AvgRequest.newBuilder().setNumber(number).build())
53 | );
54 |
55 | stream.onCompleted();
56 | latch.await();
57 | }
58 |
59 | private static void doMax(ManagedChannel channel) throws InterruptedException {
60 | System.out.println("Enter doMax");
61 | CalculatorServiceGrpc.CalculatorServiceStub stub = CalculatorServiceGrpc.newStub(channel);
62 | CountDownLatch latch = new CountDownLatch(1);
63 |
64 | StreamObserver stream = stub.max(new StreamObserver() {
65 | @Override
66 | public void onNext(MaxResponse response) {
67 | System.out.println("Max = " + response.getMax());
68 | }
69 |
70 | @Override
71 | public void onError(Throwable t) {}
72 |
73 | @Override
74 | public void onCompleted() {
75 | latch.countDown();
76 | }
77 | });
78 |
79 | Arrays.asList(1, 5, 3, 6, 2, 20).forEach(number ->
80 | stream.onNext(MaxRequest.newBuilder().setNumber(number).build())
81 | );
82 |
83 | stream.onCompleted();
84 |
85 | //noinspection ResultOfMethodCallIgnored
86 | latch.await(3, TimeUnit.SECONDS);
87 | }
88 |
89 | private static void doSqrt(CalculatorServiceGrpc.CalculatorServiceBlockingStub stub) {
90 | System.out.println("Enter doSqrt");
91 | SqrtResponse response = stub.sqrt(SqrtRequest.newBuilder().setNumber(25).build());
92 |
93 | System.out.println("Sqrt 25 = " + response.getResult());
94 |
95 | try {
96 | response = stub.sqrt(SqrtRequest.newBuilder().setNumber(-1).build());
97 | System.out.println("Sqrt -1 = " + response.getResult());
98 | } catch (RuntimeException e) {
99 | System.out.println("Got an exception for sqrt");
100 | e.printStackTrace();
101 | }
102 | }
103 |
104 | public static void main(String[] args) throws InterruptedException {
105 | if (args.length == 0) {
106 | System.out.println("Need one argument to work");
107 | return;
108 | }
109 |
110 | ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50052)
111 | .usePlaintext()
112 | .build();
113 |
114 | switch (args[0]) {
115 | case "sum": doSum(channel); break;
116 | case "primes": doPrimes(channel); break;
117 | case "avg": doAvg(channel); break;
118 | case "max": doMax(channel); break;
119 | case "sqrt": {
120 | CalculatorServiceGrpc.CalculatorServiceBlockingStub stub = CalculatorServiceGrpc.newBlockingStub(channel);
121 | doSqrt(stub);
122 | break;
123 | }
124 | default: System.out.println("Keyword Invalid: " + args[0]);
125 | }
126 |
127 | System.out.println("Shutting Down");
128 | channel.shutdown();
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/main/java/calculator/server/CalculatorServer.java:
--------------------------------------------------------------------------------
1 | package calculator.server;
2 |
3 | import io.grpc.Server;
4 | import io.grpc.ServerBuilder;
5 |
6 | import java.io.IOException;
7 |
8 | public final class CalculatorServer {
9 | public static void main(String[] args) throws IOException, InterruptedException {
10 | int port = 50052;
11 |
12 | Server server = ServerBuilder.forPort(port)
13 | .addService(new CalculatorServiceImpl())
14 | .build();
15 |
16 | server.start();
17 | System.out.println("Server Started");
18 | System.out.println("Listening on port: " + port);
19 |
20 | Runtime.getRuntime().addShutdownHook(new Thread(() -> {
21 | System.out.println("Received Shutdown Request");
22 | server.shutdown();
23 | System.out.println("Server Stopped");
24 | }));
25 |
26 | server.awaitTermination();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/calculator/server/CalculatorServiceImpl.java:
--------------------------------------------------------------------------------
1 | package calculator.server;
2 |
3 | import com.proto.calculator.*;
4 | import io.grpc.Status;
5 | import io.grpc.stub.StreamObserver;
6 |
7 | public final class CalculatorServiceImpl extends CalculatorServiceGrpc.CalculatorServiceImplBase {
8 | @Override
9 | public void sum(SumRequest request, StreamObserver responseObserver) {
10 | responseObserver.onNext(SumResponse.newBuilder().setResult(
11 | request.getFirstNumber() + request.getSecondNumber()
12 | ).build());
13 | responseObserver.onCompleted();
14 | }
15 |
16 | @Override
17 | public void primes(PrimeRequest request, StreamObserver responseObserver) {
18 | int number = request.getNumber();
19 | int divisor = 2;
20 |
21 | while (number > 1) {
22 | if (number % divisor == 0) {
23 | number /= divisor;
24 | responseObserver.onNext(PrimeResponse.newBuilder().setPrimeFactor(divisor).build());
25 | } else {
26 | ++divisor;
27 | }
28 | }
29 |
30 | responseObserver.onCompleted();
31 | }
32 |
33 | @Override
34 | public StreamObserver avg(StreamObserver responseObserver) {
35 | return new StreamObserver() {
36 | int sum = 0;
37 | int count = 0;
38 |
39 | @Override
40 | public void onNext(AvgRequest value) {
41 | sum += value.getNumber();
42 | ++count;
43 | }
44 |
45 | @Override
46 | public void onError(Throwable t) {
47 | responseObserver.onError(t);
48 | }
49 |
50 | @Override
51 | public void onCompleted() {
52 | responseObserver.onNext(AvgResponse.newBuilder().setResult(
53 | (double) sum / count
54 | ).build());
55 | responseObserver.onCompleted();
56 | }
57 | };
58 | }
59 |
60 | @Override
61 | public StreamObserver max(StreamObserver responseObserver) {
62 | return new StreamObserver() {
63 | int max = 0;
64 |
65 | @Override
66 | public void onNext(MaxRequest value) {
67 | if (value.getNumber() > max) {
68 | max = value.getNumber();
69 | responseObserver.onNext(MaxResponse.newBuilder().setMax(max).build());
70 | }
71 | }
72 |
73 | @Override
74 | public void onError(Throwable t) {
75 | responseObserver.onError(t);
76 | }
77 |
78 | @Override
79 | public void onCompleted() {
80 | responseObserver.onCompleted();
81 | }
82 | };
83 | }
84 |
85 | @Override
86 | public void sqrt(SqrtRequest request, StreamObserver responseObserver) {
87 | int number = request.getNumber();
88 |
89 | if (number < 0) {
90 | responseObserver.onError(Status.INVALID_ARGUMENT
91 | .withDescription("The number being sent cannot be negative")
92 | .augmentDescription("Number: " + number)
93 | .asRuntimeException());
94 | return;
95 | }
96 |
97 | responseObserver.onNext(
98 | SqrtResponse.newBuilder().setResult(Math.sqrt(number)).build()
99 | );
100 | responseObserver.onCompleted();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/greeting/client/AddHeaderInterceptor.java:
--------------------------------------------------------------------------------
1 | package greeting.client;
2 |
3 | import io.grpc.*;
4 |
5 | import static greeting.server.HeaderCheckInterceptor.CUSTOM_HEADER_KEY;
6 |
7 | public final class AddHeaderInterceptor implements ClientInterceptor {
8 | @Override
9 | public ClientCall interceptCall(MethodDescriptor method, CallOptions callOptions, Channel next) {
10 | return new ForwardingClientCall.SimpleForwardingClientCall(next.newCall(method, callOptions)) {
11 | @Override
12 | public void start(Listener responseListener, Metadata headers) {
13 | headers.put(CUSTOM_HEADER_KEY, "customRequestValue");
14 | super.start(responseListener, headers);
15 | }
16 | };
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/greeting/client/GreetingClient.java:
--------------------------------------------------------------------------------
1 | package greeting.client;
2 |
3 | import com.proto.greeting.*;
4 | import io.grpc.*;
5 | import io.grpc.stub.StreamObserver;
6 |
7 | import java.util.Arrays;
8 | import java.util.concurrent.CountDownLatch;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | public final class GreetingClient {
12 | private static void doGreet(ManagedChannel channel) {
13 | System.out.println("Enter doGreet");
14 | GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel);
15 | GreetingResponse response = stub.greet(GreetingRequest.newBuilder().setFirstName("Clement").build());
16 |
17 | System.out.println("Greeting: " + response.getResult());
18 | }
19 |
20 | private static void doGreetManyTimes(ManagedChannel channel) {
21 | System.out.println("Enter doGreetManyTimes");
22 | GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel);
23 |
24 | stub.greetManyTimes(GreetingRequest.newBuilder().setFirstName("Clement").build()).forEachRemaining(response ->
25 | System.out.println(response.getResult())
26 | );
27 | }
28 |
29 | private static void doLongGreet(ManagedChannel channel) throws InterruptedException {
30 | System.out.println("Enter doLongGreet");
31 | GreetingServiceGrpc.GreetingServiceStub stub = GreetingServiceGrpc.newStub(channel);
32 | CountDownLatch latch = new CountDownLatch(1);
33 |
34 | StreamObserver stream = stub.longGreet(new StreamObserver() {
35 | @Override
36 | public void onNext(GreetingResponse response) {
37 | System.out.println(response.getResult());
38 | }
39 |
40 | @Override
41 | public void onError(Throwable t) {}
42 |
43 | @Override
44 | public void onCompleted() {
45 | latch.countDown();
46 | }
47 | });
48 |
49 | Arrays.asList("Clement", "Marie", "Test").forEach(name ->
50 | stream.onNext(GreetingRequest.newBuilder().setFirstName(name).build())
51 | );
52 |
53 | stream.onCompleted();
54 |
55 | //noinspection ResultOfMethodCallIgnored
56 | latch.await(3, TimeUnit.SECONDS);
57 | }
58 |
59 | private static void doGreetEveryone(ManagedChannel channel) throws InterruptedException {
60 | System.out.println("Enter doGreetEveryone");
61 | GreetingServiceGrpc.GreetingServiceStub stub = GreetingServiceGrpc.newStub(channel);
62 | CountDownLatch latch = new CountDownLatch(1);
63 |
64 | StreamObserver stream = stub.greetEveryone(new StreamObserver() {
65 | @Override
66 | public void onNext(GreetingResponse response) {
67 | System.out.println(response.getResult());
68 | }
69 |
70 | @Override
71 | public void onError(Throwable t) {}
72 |
73 | @Override
74 | public void onCompleted() {
75 | latch.countDown();
76 | }
77 | });
78 |
79 | Arrays.asList("Clement", "Marie", "Test").forEach(name ->
80 | stream.onNext(GreetingRequest.newBuilder().setFirstName(name).build())
81 | );
82 |
83 | stream.onCompleted();
84 |
85 | //noinspection ResultOfMethodCallIgnored
86 | latch.await(3, TimeUnit.SECONDS);
87 | }
88 |
89 | private static void doGreetWithDeadline(ManagedChannel channel) {
90 | System.out.println("Enter doGreetWithDeadline");
91 | GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel);
92 | GreetingRequest request = GreetingRequest.newBuilder().setFirstName("Clement").build();
93 | GreetingResponse response = stub.withDeadline(Deadline.after(3, TimeUnit.SECONDS))
94 | .greetWithDeadline(request);
95 |
96 | System.out.println("Greeting within deadline: " + response.getResult());
97 |
98 | try {
99 | response = stub.withDeadline(Deadline.after(100, TimeUnit.MILLISECONDS))
100 | .greetWithDeadline(request);
101 |
102 | System.out.println("Greeting deadline exceeded: " + response.getResult());
103 | } catch (StatusRuntimeException e) {
104 | if (e.getStatus().getCode() == Status.Code.DEADLINE_EXCEEDED) {
105 | System.out.println("Deadline has been exceeded");
106 | } else {
107 | System.out.println("Got an exception in greetWithDeadline");
108 | e.printStackTrace();
109 | }
110 | }
111 | }
112 |
113 | public static void main(String[] args) throws InterruptedException {
114 | if (args.length == 0) {
115 | System.out.println("Need one argument to work");
116 | return;
117 | }
118 |
119 | ManagedChannel channel = ManagedChannelBuilder
120 | .forAddress("localhost", 50051)
121 | .intercept(new LogInterceptor())
122 | .intercept(new AddHeaderInterceptor())
123 | .usePlaintext()
124 | .build();
125 |
126 | switch (args[0]) {
127 | case "greet": doGreet(channel); break;
128 | case "greet_many_times": doGreetManyTimes(channel); break;
129 | case "greet_long": doLongGreet(channel); break;
130 | case "greet_everyone": doGreetEveryone(channel); break;
131 | case "greet_with_deadline": doGreetWithDeadline(channel); break;
132 | default: System.out.println("Keyword Invalid: " + args[0]);
133 | }
134 |
135 | System.out.println("Shutting Down");
136 | channel.shutdown();
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/main/java/greeting/client/GreetingClientTls.java:
--------------------------------------------------------------------------------
1 | package greeting.client;
2 |
3 | import com.proto.greeting.GreetingRequest;
4 | import com.proto.greeting.GreetingResponse;
5 | import com.proto.greeting.GreetingServiceGrpc;
6 | import io.grpc.*;
7 |
8 | import java.io.File;
9 | import java.io.IOException;
10 |
11 | public final class GreetingClientTls {
12 | private static void doGreet(ManagedChannel channel) {
13 | System.out.println("Enter doGreet");
14 | GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel);
15 | GreetingResponse response = stub.greet(GreetingRequest.newBuilder().setFirstName("Clement").build());
16 |
17 | System.out.println("Greeting: " + response.getResult());
18 | }
19 |
20 | public static void main(String[] args) throws IOException {
21 | ChannelCredentials creds = TlsChannelCredentials.newBuilder().trustManager(
22 | new File("ssl/ca.crt")
23 | ).build();
24 | ManagedChannel channel = Grpc.newChannelBuilderForAddress("localhost", 50051, creds).build();
25 |
26 | doGreet(channel);
27 |
28 | System.out.println("Shutting Down");
29 | channel.shutdown();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/greeting/client/LogInterceptor.java:
--------------------------------------------------------------------------------
1 | package greeting.client;
2 |
3 | import io.grpc.*;
4 |
5 | public final class LogInterceptor implements ClientInterceptor {
6 | @Override
7 | public ClientCall interceptCall(MethodDescriptor method, CallOptions callOptions, Channel next) {
8 | return new ForwardingClientCall.SimpleForwardingClientCall(next.newCall(method, callOptions)) {
9 | @Override
10 | public void sendMessage(ReqT message) {
11 | System.out.println("Send a message");
12 | System.out.println(message);
13 |
14 | System.out.println("With call options");
15 | System.out.println(callOptions.toString());
16 | super.sendMessage(message);
17 | }
18 | };
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/greeting/server/GreetingServer.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import io.grpc.Server;
4 | import io.grpc.ServerBuilder;
5 | import io.grpc.protobuf.services.ProtoReflectionService;
6 |
7 | import java.io.IOException;
8 |
9 | public final class GreetingServer {
10 | public static void main(String[] args) throws IOException, InterruptedException {
11 | int port = 50051;
12 |
13 | Server server = ServerBuilder.forPort(port)
14 | .addService(new GreetingServiceImpl(new SleeperImpl()))
15 | .addService(ProtoReflectionService.newInstance())
16 | .intercept(new LogInterceptor())
17 | .intercept(new HeaderCheckInterceptor())
18 | .build();
19 |
20 | server.start();
21 | System.out.println("Server Started");
22 | System.out.println("Listening on port: " + port);
23 |
24 | Runtime.getRuntime().addShutdownHook(new Thread(() -> {
25 | System.out.println("Received Shutdown Request");
26 | server.shutdown();
27 | System.out.println("Server Stopped");
28 | }));
29 |
30 | server.awaitTermination();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/greeting/server/GreetingServerTls.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import io.grpc.Server;
4 | import io.grpc.ServerBuilder;
5 |
6 | import java.io.File;
7 | import java.io.IOException;
8 |
9 | public final class GreetingServerTls {
10 | public static void main(String[] args) throws IOException, InterruptedException {
11 | int port = 50051;
12 |
13 | Server server = ServerBuilder.forPort(port)
14 | .useTransportSecurity(
15 | new File("ssl/server.crt"),
16 | new File("ssl/server.pem")
17 | )
18 | .addService(new GreetingServiceImpl(new SleeperImpl()))
19 | .build();
20 |
21 | server.start();
22 | System.out.println("Server Started");
23 | System.out.println("Listening on port: " + port);
24 |
25 | Runtime.getRuntime().addShutdownHook(new Thread(() -> {
26 | System.out.println("Received Shutdown Request");
27 | server.shutdown();
28 | System.out.println("Server Stopped");
29 | }));
30 |
31 | server.awaitTermination();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/greeting/server/GreetingServiceImpl.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import com.proto.greeting.GreetingRequest;
4 | import com.proto.greeting.GreetingResponse;
5 | import com.proto.greeting.GreetingServiceGrpc;
6 | import io.grpc.Context;
7 | import io.grpc.stub.StreamObserver;
8 | import utils.Sleeper;
9 |
10 | public final class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
11 |
12 | final Sleeper sleeper;
13 |
14 | GreetingServiceImpl(Sleeper sleeper) {
15 | this.sleeper = sleeper;
16 | }
17 |
18 | @Override
19 | public void greet(GreetingRequest request, StreamObserver responseObserver) {
20 | responseObserver.onNext(GreetingResponse.newBuilder().setResult("Hello " + request.getFirstName()).build());
21 | responseObserver.onCompleted();
22 | }
23 |
24 | @Override
25 | public void greetManyTimes(GreetingRequest request, StreamObserver responseObserver) {
26 | GreetingResponse response = GreetingResponse.newBuilder().setResult("Hello " + request.getFirstName()).build();
27 |
28 | for (int i = 0; i < 10; ++i) {
29 | responseObserver.onNext(response);
30 | }
31 |
32 | responseObserver.onCompleted();
33 | }
34 |
35 | @Override
36 | public StreamObserver longGreet(StreamObserver responseObserver) {
37 | StringBuilder sb = new StringBuilder();
38 |
39 | return new StreamObserver() {
40 | @Override
41 | public void onNext(GreetingRequest request) {
42 | sb.append("Hello ")
43 | .append(request.getFirstName())
44 | .append("!\n");
45 | }
46 |
47 | @Override
48 | public void onError(Throwable t) {
49 | responseObserver.onError(t);
50 | }
51 |
52 | @Override
53 | public void onCompleted() {
54 | responseObserver.onNext(GreetingResponse.newBuilder().setResult(sb.toString()).build());
55 | responseObserver.onCompleted();
56 | }
57 | };
58 | }
59 |
60 | @Override
61 | public StreamObserver greetEveryone(StreamObserver responseObserver) {
62 | return new StreamObserver() {
63 | @Override
64 | public void onNext(GreetingRequest request) {
65 | responseObserver.onNext(GreetingResponse.newBuilder().setResult("Hello " + request.getFirstName()).build());
66 | }
67 |
68 | @Override
69 | public void onError(Throwable t) {
70 | responseObserver.onError(t);
71 | }
72 |
73 | @Override
74 | public void onCompleted() {
75 | responseObserver.onCompleted();
76 | }
77 | };
78 | }
79 |
80 | @Override
81 | public void greetWithDeadline(GreetingRequest request, StreamObserver responseObserver) {
82 | Context current = Context.current();
83 |
84 | try {
85 | for (int i = 0; i < 3; ++i) {
86 | if (current.isCancelled())
87 | return;
88 |
89 | sleeper.sleep(100);
90 | }
91 |
92 | responseObserver.onNext(GreetingResponse.newBuilder().setResult("Hello " + request.getFirstName()).build());
93 | responseObserver.onCompleted();
94 | } catch (InterruptedException e) {
95 | responseObserver.onError(e);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/greeting/server/HeaderCheckInterceptor.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import com.google.common.annotations.VisibleForTesting;
4 | import io.grpc.*;
5 |
6 | public final class HeaderCheckInterceptor implements ServerInterceptor {
7 |
8 | @VisibleForTesting
9 | public static final Metadata.Key CUSTOM_HEADER_KEY =
10 | Metadata.Key.of("custom_server_header_key", Metadata.ASCII_STRING_MARSHALLER);
11 |
12 | @Override
13 | public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, ServerCallHandler next) {
14 | if (!headers.containsKey(CUSTOM_HEADER_KEY)) {
15 | call.close(Status.CANCELLED, new Metadata());
16 | return new ServerCall.Listener() {};
17 | }
18 |
19 | return new ForwardingServerCallListener.SimpleForwardingServerCallListener(next.startCall(call, headers)) {};
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/greeting/server/LogInterceptor.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import io.grpc.*;
4 |
5 | public final class LogInterceptor implements ServerInterceptor {
6 | @Override
7 | public ServerCall.Listener interceptCall(ServerCall call, Metadata headers, ServerCallHandler next) {
8 | return new ForwardingServerCallListener.SimpleForwardingServerCallListener(next.startCall(call, headers)) {
9 | @Override
10 | public void onMessage(ReqT message) {
11 | System.out.println("Receive a message");
12 | System.out.println(message);
13 |
14 | System.out.println("With headers");
15 | System.out.println(headers);
16 | super.onMessage(message);
17 | }
18 | };
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/greeting/server/SleeperImpl.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import utils.Sleeper;
4 |
5 | public class SleeperImpl implements Sleeper {
6 |
7 | @Override
8 | public void sleep(long millis) throws InterruptedException {
9 | Thread.sleep(millis);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/utils/ExcludeFromJacocoGeneratedReport.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Retention(RetentionPolicy.RUNTIME)
9 | @Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
10 | public @interface ExcludeFromJacocoGeneratedReport {}
11 |
--------------------------------------------------------------------------------
/src/main/java/utils/Sleeper.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | public interface Sleeper {
4 | void sleep(long millis) throws InterruptedException;
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/proto/blog/blog.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package blog;
4 |
5 | import "google/protobuf/empty.proto";
6 |
7 | option java_package = "com.proto.blog";
8 | option java_multiple_files = true;
9 |
10 | message Blog {
11 | string id = 1;
12 | string author = 2;
13 | string title = 3;
14 | string content = 4;
15 | }
16 |
17 | message BlogId {
18 | string id = 1;
19 | }
20 |
21 | service BlogService {
22 | // Requests the creation for a Blog
23 | // Returns Status.INTERNAL if the blog couldn't be created due to Db error
24 | // Returns the created Blog's Id
25 | rpc CreateBlog(Blog) returns (BlogId);
26 |
27 | // Requests access to the content of a Blog by sending an Id
28 | // Returns Status.NOT_FOUND if the Id doesn't match any Blog in Db
29 | // Returns Blog content
30 | rpc ReadBlog(BlogId) returns (Blog);
31 |
32 | // Requests the update of a Blog in Db
33 | // Returns Status.NOT_FOUND if the Id doesn't match any Blog in Db
34 | // Returns Status.INTERNAL if the blog couldn't be updated due to Db error
35 | // Returns Empty
36 | rpc UpdateBlog(Blog) returns (google.protobuf.Empty);
37 |
38 | // Requests the delete of a Blog in Db by giving its Id
39 | // Returns Status.NOT_FOUND if the Id doesn't match any Blog in Db
40 | // Returns Status.INTERNAL if the blog couldn't be deleted due to Db error
41 | // Returns Empty
42 | rpc DeleteBlog(BlogId) returns (google.protobuf.Empty);
43 |
44 | // Requests access to all the Blogs in Db
45 | // Returns stream of Blogs
46 | rpc ListBlogs(google.protobuf.Empty) returns (stream Blog);
47 | }
--------------------------------------------------------------------------------
/src/main/proto/calculator/avg.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package calculator;
4 |
5 | option java_package = "com.proto.calculator";
6 | option java_multiple_files = true;
7 |
8 | message AvgRequest {
9 | int32 number = 1;
10 | }
11 |
12 | message AvgResponse {
13 | double result = 1;
14 | }
--------------------------------------------------------------------------------
/src/main/proto/calculator/calculator.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package calculator;
4 |
5 | import "calculator/avg.proto";
6 | import "calculator/max.proto";
7 | import "calculator/prime.proto";
8 | import "calculator/sqrt.proto";
9 | import "calculator/sum.proto";
10 |
11 | option java_package = "com.proto.calculator";
12 | option java_multiple_files = true;
13 |
14 | service CalculatorService {
15 | rpc Sum(SumRequest) returns (SumResponse);
16 | rpc Primes(PrimeRequest) returns (stream PrimeResponse);
17 | rpc Avg(stream AvgRequest) returns (AvgResponse);
18 | rpc Max(stream MaxRequest) returns (stream MaxResponse);
19 |
20 | // Returns a Status.INVALID_ARGUMENT if the SqrtRequest.number is negative
21 | rpc Sqrt(SqrtRequest) returns (SqrtResponse);
22 | }
--------------------------------------------------------------------------------
/src/main/proto/calculator/max.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package calculator;
4 |
5 | option java_package = "com.proto.calculator";
6 | option java_multiple_files = true;
7 |
8 | message MaxRequest {
9 | int32 number = 1;
10 | }
11 |
12 | message MaxResponse {
13 | int32 max = 1;
14 | }
--------------------------------------------------------------------------------
/src/main/proto/calculator/prime.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package calculator;
4 |
5 | option java_package = "com.proto.calculator";
6 | option java_multiple_files = true;
7 |
8 | message PrimeRequest {
9 | int32 number = 1;
10 | }
11 |
12 | message PrimeResponse {
13 | int32 prime_factor = 1;
14 | }
--------------------------------------------------------------------------------
/src/main/proto/calculator/sqrt.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package calculator;
4 |
5 | option java_package = "com.proto.calculator";
6 | option java_multiple_files = true;
7 |
8 | message SqrtRequest {
9 | int32 number = 1;
10 | }
11 |
12 | message SqrtResponse {
13 | double result = 1;
14 | }
--------------------------------------------------------------------------------
/src/main/proto/calculator/sum.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package calculator;
4 |
5 | option java_package = "com.proto.calculator";
6 | option java_multiple_files = true;
7 |
8 | message SumRequest {
9 | int32 first_number = 1;
10 | int32 second_number = 2;
11 | };
12 |
13 | message SumResponse {
14 | int32 result = 1;
15 | }
--------------------------------------------------------------------------------
/src/main/proto/dummy.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package dummy;
4 |
5 | option java_package = "com.proto.dummy";
6 | option java_multiple_files = true;
7 |
8 | message DummyMessage {
9 |
10 | }
11 |
12 | service DummyService {
13 |
14 | }
--------------------------------------------------------------------------------
/src/main/proto/greeting/greeting.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package greeting;
4 |
5 | option java_package = "com.proto.greeting";
6 | option java_multiple_files = true;
7 |
8 | message GreetingRequest {
9 | string first_name = 1;
10 | }
11 |
12 | message GreetingResponse {
13 | string result = 1;
14 | }
15 |
16 | service GreetingService {
17 | rpc Greet(GreetingRequest) returns (GreetingResponse);
18 | rpc GreetManyTimes(GreetingRequest) returns (stream GreetingResponse);
19 | rpc LongGreet(stream GreetingRequest) returns (GreetingResponse);
20 | rpc GreetEveryone(stream GreetingRequest) returns (stream GreetingResponse);
21 | rpc GreetWithDeadline(GreetingRequest) returns (GreetingResponse);
22 | }
--------------------------------------------------------------------------------
/src/test/java/blog/client/BlogCreateTest.java:
--------------------------------------------------------------------------------
1 | package blog.client;
2 |
3 | import com.proto.blog.Blog;
4 | import com.proto.blog.BlogId;
5 | import com.proto.blog.BlogServiceGrpc;
6 | import io.grpc.Status;
7 | import io.grpc.stub.StreamObserver;
8 | import org.junit.jupiter.api.Test;
9 | import utils.ClientTestBase;
10 |
11 | import java.io.IOException;
12 |
13 | import static org.junit.jupiter.api.Assertions.assertNotNull;
14 | import static org.junit.jupiter.api.Assertions.assertNull;
15 |
16 | public class BlogCreateTest extends ClientTestBase {
17 | private static class CreateSuccessBlogServer extends BlogServiceGrpc.BlogServiceImplBase {
18 | @Override
19 | public void createBlog(Blog request, StreamObserver responseObserver) {
20 | responseObserver.onNext(BlogId.newBuilder().setId("this_is_an_id").build());
21 | responseObserver.onCompleted();
22 | }
23 | }
24 |
25 | private static class CreateFailBlogServer extends BlogServiceGrpc.BlogServiceImplBase {
26 | @Override
27 | public void createBlog(Blog request, StreamObserver responseObserver) {
28 | responseObserver.onError(Status.INTERNAL.asRuntimeException());
29 | }
30 | }
31 |
32 | @Test
33 | void createTest() throws IOException {
34 | createServerWithService(new CreateSuccessBlogServer(), BlogServiceGrpc::newBlockingStub);
35 |
36 | assertNotNull(BlogClient.createBlog(getStub()));
37 | }
38 |
39 | @Test
40 | void createFailTest() throws IOException {
41 | createServerWithService(new CreateFailBlogServer(), BlogServiceGrpc::newBlockingStub);
42 |
43 | assertNull(BlogClient.createBlog(getStub()));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/java/blog/client/BlogDeleteTest.java:
--------------------------------------------------------------------------------
1 | package blog.client;
2 |
3 | import com.google.protobuf.Empty;
4 | import com.proto.blog.BlogId;
5 | import com.proto.blog.BlogServiceGrpc;
6 | import io.grpc.Status;
7 | import io.grpc.stub.StreamObserver;
8 | import org.junit.jupiter.api.Test;
9 | import utils.ClientTestBase;
10 |
11 | import java.io.IOException;
12 |
13 | import static org.junit.jupiter.api.Assertions.assertNotNull;
14 | import static org.junit.jupiter.api.Assertions.assertNull;
15 |
16 | public class BlogDeleteTest extends ClientTestBase {
17 |
18 | private static class DeleteSuccessBlogServer extends BlogServiceGrpc.BlogServiceImplBase {
19 | @Override
20 | public void deleteBlog(BlogId request, StreamObserver responseObserver) {
21 | responseObserver.onNext(Empty.getDefaultInstance());
22 | responseObserver.onCompleted();
23 | }
24 | }
25 |
26 | private static class DeleteFailBlogServer extends BlogServiceGrpc.BlogServiceImplBase {
27 | @Override
28 | public void deleteBlog(BlogId request, StreamObserver responseObserver) {
29 | responseObserver.onError(Status.NOT_FOUND.asRuntimeException());
30 | }
31 | }
32 |
33 | private final BlogId fakeBlogId = BlogId.newBuilder().setId("this_is_an_id").build();
34 |
35 | @Test
36 | void deleteTest() throws IOException {
37 | createServerWithService(new DeleteSuccessBlogServer(), BlogServiceGrpc::newBlockingStub);
38 |
39 | assertNotNull(BlogClient.deleteBlog(getStub(), fakeBlogId));
40 | }
41 |
42 | @Test
43 | void deleteFailTest() throws IOException {
44 | createServerWithService(new DeleteFailBlogServer(), BlogServiceGrpc::newBlockingStub);
45 |
46 | assertNull(BlogClient.deleteBlog(getStub(), fakeBlogId));
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/test/java/blog/client/BlogListTest.java:
--------------------------------------------------------------------------------
1 | package blog.client;
2 |
3 | import com.google.protobuf.Empty;
4 | import com.proto.blog.Blog;
5 | import com.proto.blog.BlogServiceGrpc;
6 | import io.grpc.stub.StreamObserver;
7 | import org.junit.jupiter.api.Test;
8 | import utils.ClientTestBase;
9 |
10 | import java.io.ByteArrayOutputStream;
11 | import java.io.IOException;
12 | import java.io.PrintStream;
13 |
14 | import static org.junit.jupiter.api.Assertions.assertEquals;
15 |
16 | public class BlogListTest extends ClientTestBase {
17 |
18 | private static class ListEmptyBlogServer extends BlogServiceGrpc.BlogServiceImplBase {
19 | @Override
20 | public void listBlogs(Empty request, StreamObserver responseObserver) {
21 | responseObserver.onCompleted();
22 | }
23 | }
24 |
25 | private static class ListNonEmptyBlogServer extends BlogServiceGrpc.BlogServiceImplBase {
26 | @Override
27 | public void listBlogs(Empty request, StreamObserver responseObserver) {
28 | responseObserver.onNext(Blog.newBuilder()
29 | .setId("id")
30 | .setAuthor("Clement")
31 | .setTitle("Title")
32 | .setContent("Content")
33 | .build()
34 | );
35 | responseObserver.onCompleted();
36 | }
37 | }
38 |
39 | @Test
40 | void listEmptyTest() throws IOException {
41 | createServerWithService(new ListEmptyBlogServer(), BlogServiceGrpc::newBlockingStub);
42 | ByteArrayOutputStream outSpy = new ByteArrayOutputStream();
43 | PrintStream ps = new PrintStream(outSpy);
44 |
45 | BlogClient.listBlogs(getStub(), ps);
46 | assertEquals("Listing blogs...\n", outSpy.toString());
47 | }
48 |
49 | @Test
50 | void listNonEmptyTest() throws IOException {
51 | createServerWithService(new ListNonEmptyBlogServer(), BlogServiceGrpc::newBlockingStub);
52 | ByteArrayOutputStream outSpy = new ByteArrayOutputStream();
53 | PrintStream ps = new PrintStream(outSpy);
54 |
55 | BlogClient.listBlogs(getStub(), ps);
56 | assertEquals(
57 | "Listing blogs...\n" +
58 | "id: \"id\"\n" +
59 | "author: \"Clement\"\n" +
60 | "title: \"Title\"\n" +
61 | "content: \"Content\"\n",
62 | outSpy.toString()
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/test/java/blog/client/BlogReadTest.java:
--------------------------------------------------------------------------------
1 | package blog.client;
2 |
3 | import com.proto.blog.Blog;
4 | import com.proto.blog.BlogId;
5 | import com.proto.blog.BlogServiceGrpc;
6 | import io.grpc.Status;
7 | import io.grpc.stub.StreamObserver;
8 | import org.junit.jupiter.api.Test;
9 | import utils.ClientTestBase;
10 |
11 | import java.io.IOException;
12 |
13 | import static org.junit.jupiter.api.Assertions.assertNotNull;
14 | import static org.junit.jupiter.api.Assertions.assertNull;
15 |
16 | public class BlogReadTest extends ClientTestBase {
17 |
18 | private static class ReadSuccessBlogServer extends BlogServiceGrpc.BlogServiceImplBase {
19 |
20 | @Override
21 | public void readBlog(BlogId request, StreamObserver responseObserver) {
22 | responseObserver.onNext(Blog.getDefaultInstance());
23 | responseObserver.onCompleted();
24 | }
25 | }
26 |
27 | private static class ReadFailBlogServer extends BlogServiceGrpc.BlogServiceImplBase {
28 | @Override
29 | public void readBlog(BlogId request, StreamObserver responseObserver) {
30 | responseObserver.onError(Status.NOT_FOUND.asRuntimeException());
31 | }
32 | }
33 |
34 | private final BlogId fakeBlogId = BlogId.newBuilder().setId("this_is_an_id").build();
35 |
36 | @Test
37 | void readTest() throws IOException {
38 | createServerWithService(new ReadSuccessBlogServer(), BlogServiceGrpc::newBlockingStub);
39 |
40 | assertNotNull(BlogClient.readBlog(getStub(), fakeBlogId));
41 | }
42 |
43 | @Test
44 | void deleteFailTest() throws IOException {
45 | createServerWithService(new ReadFailBlogServer(), BlogServiceGrpc::newBlockingStub);
46 |
47 | assertNull(BlogClient.readBlog(getStub(), fakeBlogId));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/java/blog/client/BlogUpdateTest.java:
--------------------------------------------------------------------------------
1 | package blog.client;
2 |
3 | import com.google.protobuf.Empty;
4 | import com.proto.blog.Blog;
5 | import com.proto.blog.BlogId;
6 | import com.proto.blog.BlogServiceGrpc;
7 | import io.grpc.Status;
8 | import io.grpc.stub.StreamObserver;
9 | import org.junit.jupiter.api.Test;
10 | import utils.ClientTestBase;
11 |
12 | import java.io.IOException;
13 |
14 | import static org.junit.jupiter.api.Assertions.assertNotNull;
15 | import static org.junit.jupiter.api.Assertions.assertNull;
16 |
17 | public class BlogUpdateTest extends ClientTestBase {
18 |
19 | private static class UpdateSuccessBlogServer extends BlogServiceGrpc.BlogServiceImplBase {
20 |
21 | @Override
22 | public void updateBlog(Blog request, StreamObserver responseObserver) {
23 | responseObserver.onNext(Empty.getDefaultInstance());
24 | responseObserver.onCompleted();
25 | }
26 | }
27 |
28 | private static class UpdateFailBlogServer extends BlogServiceGrpc.BlogServiceImplBase {
29 | @Override
30 | public void updateBlog(Blog request, StreamObserver responseObserver) {
31 | responseObserver.onError(Status.NOT_FOUND.asRuntimeException());
32 | }
33 | }
34 |
35 | private final BlogId blogId = BlogId.newBuilder().setId("this_is_an_id").build();
36 |
37 | @Test
38 | void updateTest() throws IOException {
39 | createServerWithService(new UpdateSuccessBlogServer(), BlogServiceGrpc::newBlockingStub);
40 |
41 | assertNotNull(BlogClient.updateBlog(getStub(), blogId));
42 | }
43 |
44 | @Test
45 | void updateFailTest() throws IOException {
46 | createServerWithService(new UpdateFailBlogServer(), BlogServiceGrpc::newBlockingStub);
47 |
48 | assertNull(BlogClient.updateBlog(getStub(), blogId));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/java/blog/server/BlogCreateTest.java:
--------------------------------------------------------------------------------
1 | package blog.server;
2 |
3 | import com.mongodb.MongoException;
4 | import com.mongodb.client.MongoClient;
5 | import com.mongodb.client.MongoCollection;
6 | import com.mongodb.client.MongoDatabase;
7 | import com.mongodb.client.result.InsertOneResult;
8 | import com.proto.blog.Blog;
9 | import com.proto.blog.BlogId;
10 | import com.proto.blog.BlogServiceGrpc;
11 | import io.grpc.Status;
12 | import io.grpc.StatusRuntimeException;
13 | import org.bson.BsonObjectId;
14 | import org.bson.Document;
15 | import org.bson.types.ObjectId;
16 | import org.junit.jupiter.api.Test;
17 | import org.mockito.Mock;
18 | import org.mockito.MockitoAnnotations;
19 | import utils.ServerTestBase;
20 |
21 | import static org.junit.jupiter.api.Assertions.*;
22 | import static org.mockito.ArgumentMatchers.any;
23 | import static org.mockito.ArgumentMatchers.anyString;
24 | import static org.mockito.Mockito.when;
25 |
26 | public class BlogCreateTest extends ServerTestBase<
27 | BlogServiceGrpc.BlogServiceBlockingStub,
28 | BlogServiceGrpc.BlogServiceStub
29 | > {
30 |
31 | @Mock
32 | private MongoClient mockClient;
33 | @Mock
34 | private MongoCollection mockCollection;
35 | @Mock
36 | private MongoDatabase mockDB;
37 |
38 | final String author = "Clement";
39 | final String title = "My Blog";
40 | final String content = "This is a cool blog";
41 |
42 | BlogCreateTest() {
43 | MockitoAnnotations.openMocks(this);
44 | when(mockClient.getDatabase(anyString())).thenReturn(mockDB);
45 | when(mockDB.getCollection(anyString())).thenReturn(mockCollection);
46 | addService(new BlogServiceImpl(mockClient));
47 | setBlockingStubInstantiator(BlogServiceGrpc::newBlockingStub);
48 | }
49 |
50 | @Test
51 | void createTest() {
52 | ObjectId id = new ObjectId("579397d20c2dd41b9a8a09eb");
53 |
54 | Document blog = new Document()
55 | .append("author", author)
56 | .append("title", title)
57 | .append("content", content);
58 |
59 | when(mockCollection.insertOne(blog)).thenReturn(InsertOneResult.acknowledged(new BsonObjectId(id)));
60 |
61 | BlogId blogId = blockingStub.createBlog(
62 | Blog.newBuilder().setAuthor(author)
63 | .setTitle(title)
64 | .setContent(content)
65 | .build()
66 | );
67 |
68 | assertEquals(id.toString(), blogId.getId());
69 | }
70 |
71 | @Test
72 | @SuppressWarnings("ResultOfMethodCallIgnored")
73 | void createUnacknowledgedTest() {
74 | Document blog = new Document()
75 | .append("author", author)
76 | .append("title", title)
77 | .append("content", content);
78 |
79 | when(mockCollection.insertOne(blog)).thenReturn(InsertOneResult.unacknowledged());
80 |
81 | try {
82 | blockingStub.createBlog(
83 | Blog.newBuilder().setAuthor(author)
84 | .setTitle(title)
85 | .setContent(content)
86 | .build()
87 | );
88 | fail("There should be an error in this case");
89 | } catch (StatusRuntimeException e) {
90 | Status status = Status.fromThrowable(e);
91 |
92 | assertEquals(Status.Code.INTERNAL, status.getCode());
93 | assertEquals(BlogServiceImpl.BLOG_COULDNT_BE_CREATED, status.getDescription());
94 | }
95 | }
96 |
97 | @Test
98 | @SuppressWarnings("ResultOfMethodCallIgnored")
99 | void createNullIdTest() {
100 | Document blog = new Document()
101 | .append("author", author)
102 | .append("title", title)
103 | .append("content", content);
104 |
105 | when(mockCollection.insertOne(blog)).thenReturn(InsertOneResult.acknowledged(null));
106 |
107 | try {
108 | blockingStub.createBlog(
109 | Blog.newBuilder().setAuthor(author)
110 | .setTitle(title)
111 | .setContent(content)
112 | .build()
113 | );
114 | fail("There should be an error in this case");
115 | } catch (StatusRuntimeException e) {
116 | Status status = Status.fromThrowable(e);
117 |
118 | assertEquals(Status.Code.INTERNAL, status.getCode());
119 | assertEquals(BlogServiceImpl.BLOG_COULDNT_BE_CREATED, status.getDescription());
120 | }
121 | }
122 |
123 | @Test
124 | @SuppressWarnings("ResultOfMethodCallIgnored")
125 | void createErrorTest() {
126 | when(mockCollection.insertOne(any(Document.class))).thenThrow(new MongoException("A message"));
127 |
128 | try {
129 | blockingStub.createBlog(
130 | Blog.newBuilder().setAuthor(author)
131 | .setTitle(title)
132 | .setContent(content)
133 | .build()
134 | );
135 | fail("There should be an error in this case");
136 | } catch (StatusRuntimeException e) {
137 | Status status = Status.fromThrowable(e);
138 |
139 | assertEquals(Status.Code.INTERNAL, status.getCode());
140 | assertNotNull(status.getDescription());
141 | assertTrue(status.getDescription().startsWith(BlogServiceImpl.BLOG_COULDNT_BE_CREATED));
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/test/java/blog/server/BlogDeleteTest.java:
--------------------------------------------------------------------------------
1 | package blog.server;
2 |
3 | import com.mongodb.MongoException;
4 | import com.mongodb.client.MongoClient;
5 | import com.mongodb.client.MongoCollection;
6 | import com.mongodb.client.MongoDatabase;
7 | import com.mongodb.client.result.DeleteResult;
8 | import com.proto.blog.BlogId;
9 | import com.proto.blog.BlogServiceGrpc;
10 | import io.grpc.Status;
11 | import io.grpc.StatusRuntimeException;
12 | import org.bson.Document;
13 | import org.bson.conversions.Bson;
14 | import org.junit.jupiter.api.Test;
15 | import org.mockito.Mock;
16 | import org.mockito.MockitoAnnotations;
17 | import utils.ServerTestBase;
18 |
19 | import static org.junit.jupiter.api.Assertions.*;
20 | import static org.mockito.ArgumentMatchers.any;
21 | import static org.mockito.ArgumentMatchers.anyString;
22 | import static org.mockito.Mockito.when;
23 |
24 | public class BlogDeleteTest extends ServerTestBase<
25 | BlogServiceGrpc.BlogServiceBlockingStub,
26 | BlogServiceGrpc.BlogServiceStub
27 | > {
28 | @Mock
29 | private MongoClient mockClient;
30 | @Mock
31 | private MongoCollection mockCollection;
32 | @Mock
33 | private MongoDatabase mockDB;
34 |
35 | final String id = "579397d20c2dd41b9a8a09eb";
36 |
37 | BlogDeleteTest() {
38 | MockitoAnnotations.openMocks(this);
39 | when(mockClient.getDatabase(anyString())).thenReturn(mockDB);
40 | when(mockDB.getCollection(anyString())).thenReturn(mockCollection);
41 | addService(new BlogServiceImpl(mockClient));
42 | setBlockingStubInstantiator(BlogServiceGrpc::newBlockingStub);
43 | }
44 |
45 | @Test
46 | void deleteTest() {
47 | when(mockCollection.deleteOne(any(Bson.class))).thenReturn(DeleteResult.acknowledged(1));
48 |
49 | assertDoesNotThrow(() -> blockingStub.deleteBlog(
50 | BlogId.newBuilder().setId(id).build()
51 | ));
52 | }
53 |
54 | @Test
55 | @SuppressWarnings("ResultOfMethodCallIgnored")
56 | void deleteInvalidIdTest() {
57 | try {
58 | blockingStub.deleteBlog(BlogId.getDefaultInstance());
59 | fail("There should be an error in this case");
60 | } catch (StatusRuntimeException e) {
61 | Status status = Status.fromThrowable(e);
62 |
63 | assertEquals(Status.Code.INVALID_ARGUMENT, status.getCode());
64 | assertEquals(BlogServiceImpl.ID_CANNOT_BE_EMPTY, status.getDescription());
65 | }
66 | }
67 |
68 | @Test
69 | @SuppressWarnings("ResultOfMethodCallIgnored")
70 | void deleteNotAcknowledgedTest() {
71 | when(mockCollection.deleteOne(any(Bson.class))).thenReturn(DeleteResult.acknowledged(0));
72 |
73 | try {
74 | blockingStub.deleteBlog(BlogId.newBuilder().setId(id).build());
75 | fail("There should be an error in this case");
76 | } catch (StatusRuntimeException e) {
77 | Status status = Status.fromThrowable(e);
78 |
79 | assertEquals(Status.Code.NOT_FOUND, status.getCode());
80 | assertNotNull(status.getDescription());
81 | assertTrue(status.getDescription().startsWith(BlogServiceImpl.BLOG_WAS_NOT_FOUND));
82 | }
83 | }
84 |
85 | @Test
86 | @SuppressWarnings("ResultOfMethodCallIgnored")
87 | void deleteNotFoundTest() {
88 | when(mockCollection.deleteOne(any(Bson.class))).thenReturn(DeleteResult.unacknowledged());
89 |
90 | try {
91 | blockingStub.deleteBlog(BlogId.newBuilder().setId(id).build());
92 | fail("There should be an error in this case");
93 | } catch (StatusRuntimeException e) {
94 | Status status = Status.fromThrowable(e);
95 |
96 | assertEquals(Status.Code.INTERNAL, status.getCode());
97 | assertEquals(BlogServiceImpl.BLOG_COULDNT_BE_DELETED, status.getDescription());
98 | }
99 | }
100 |
101 | @Test
102 | @SuppressWarnings("ResultOfMethodCallIgnored")
103 | void deleteErrorTest() {
104 | when(mockCollection.deleteOne(any(Bson.class))).thenThrow(new MongoException("A message"));
105 |
106 | try {
107 | blockingStub.deleteBlog(BlogId.newBuilder().setId(id).build());
108 | fail("There should be an error in this case");
109 | } catch (StatusRuntimeException e) {
110 | Status status = Status.fromThrowable(e);
111 |
112 | assertEquals(Status.Code.INTERNAL, status.getCode());
113 | assertNotNull(status.getDescription());
114 | assertTrue(status.getDescription().startsWith(BlogServiceImpl.BLOG_COULDNT_BE_DELETED));
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/test/java/blog/server/BlogListTest.java:
--------------------------------------------------------------------------------
1 | package blog.server;
2 |
3 | import com.mongodb.client.*;
4 | import com.proto.blog.Blog;
5 | import com.proto.blog.BlogServiceGrpc;
6 | import org.bson.Document;
7 | import org.bson.types.ObjectId;
8 | import org.junit.jupiter.api.Test;
9 | import org.mockito.Mock;
10 | import org.mockito.MockitoAnnotations;
11 | import utils.ServerTestBase;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | import static org.junit.jupiter.api.Assertions.assertEquals;
17 | import static org.mockito.ArgumentMatchers.anyString;
18 | import static org.mockito.Mockito.when;
19 |
20 | public class BlogListTest extends ServerTestBase<
21 | BlogServiceGrpc.BlogServiceBlockingStub,
22 | BlogServiceGrpc.BlogServiceStub
23 | > {
24 | @Mock
25 | private MongoClient mockClient;
26 | @Mock
27 | private MongoCollection mockCollection;
28 | @Mock
29 | private MongoDatabase mockDB;
30 | @Mock
31 | private FindIterable iterable;
32 | @Mock
33 | private MongoCursor cursor;
34 |
35 | private final List finalResult = new ArrayList<>();
36 |
37 | BlogListTest() {
38 | MockitoAnnotations.openMocks(this);
39 | when(mockClient.getDatabase(anyString())).thenReturn(mockDB);
40 | when(mockDB.getCollection(anyString())).thenReturn(mockCollection);
41 | addService(new BlogServiceImpl(mockClient));
42 | setBlockingStubInstantiator(BlogServiceGrpc::newBlockingStub);
43 | }
44 |
45 | @Test
46 | void listTest() {
47 | String author = "Clement";
48 | String title = "My Blog";
49 | String content = "This is a cool blog";
50 |
51 | Document blog1 = new Document("_id", new ObjectId("579397d20c2dd41b9a8a09eb"))
52 | .append("author", author)
53 | .append("title", title)
54 | .append("content", content);
55 | Document blog2 = new Document("_id", new ObjectId("579397d20c2dd41b9a8a09ec"))
56 | .append("author", author + "2")
57 | .append("title", title + "2")
58 | .append("content", content + "2");
59 |
60 | when(mockCollection.find()).thenReturn(iterable);
61 | when(iterable.iterator()).thenReturn(cursor);
62 | when(cursor.hasNext()).thenReturn(true, true, false);
63 | when(cursor.next()).thenReturn(blog1, blog2);
64 |
65 | blockingStub.listBlogs(com.google.protobuf.Empty.getDefaultInstance()).forEachRemaining(finalResult::add);
66 |
67 | assertEquals(2, finalResult.size());
68 | assertEquals(author, finalResult.get(0).getAuthor());
69 | assertEquals(author + "2", finalResult.get(1).getAuthor());
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/test/java/blog/server/BlogReadTest.java:
--------------------------------------------------------------------------------
1 | package blog.server;
2 |
3 | import com.mongodb.client.*;
4 | import com.proto.blog.Blog;
5 | import com.proto.blog.BlogId;
6 | import com.proto.blog.BlogServiceGrpc;
7 | import io.grpc.Status;
8 | import io.grpc.StatusRuntimeException;
9 | import org.bson.Document;
10 | import org.bson.conversions.Bson;
11 | import org.bson.types.ObjectId;
12 | import org.junit.jupiter.api.Test;
13 | import org.mockito.Mock;
14 | import org.mockito.MockitoAnnotations;
15 | import utils.ServerTestBase;
16 |
17 | import static org.junit.jupiter.api.Assertions.*;
18 | import static org.mockito.Mockito.*;
19 |
20 | public class BlogReadTest extends ServerTestBase<
21 | BlogServiceGrpc.BlogServiceBlockingStub,
22 | BlogServiceGrpc.BlogServiceStub
23 | > {
24 |
25 | @Mock
26 | private MongoClient mockClient;
27 | @Mock
28 | private MongoCollection mockCollection;
29 | @Mock
30 | private MongoDatabase mockDB;
31 | @Mock
32 | private FindIterable iterable;
33 |
34 | BlogReadTest() {
35 | MockitoAnnotations.openMocks(this);
36 | when(mockClient.getDatabase(anyString())).thenReturn(mockDB);
37 | when(mockDB.getCollection(anyString())).thenReturn(mockCollection);
38 | addService(new BlogServiceImpl(mockClient));
39 | setBlockingStubInstantiator(BlogServiceGrpc::newBlockingStub);
40 | }
41 |
42 | @Test
43 | void readTest() {
44 | String id = "579397d20c2dd41b9a8a09eb";
45 | ObjectId oid = new ObjectId(id);
46 | String author = "Clement";
47 | String title = "My Blog";
48 | String content = "This is a cool blog";
49 |
50 | Document blog = new Document("_id", oid)
51 | .append("author", author)
52 | .append("title", title)
53 | .append("content", content);
54 |
55 | when(mockCollection.find(any(Bson.class))).thenReturn(iterable);
56 | when(iterable.first()).thenReturn(blog);
57 |
58 | Blog b = blockingStub.readBlog(BlogId.newBuilder().setId(id).build());
59 |
60 | assertEquals(id, b.getId());
61 | assertEquals(author, b.getAuthor());
62 | assertEquals(title, b.getTitle());
63 | assertEquals(content, b.getContent());
64 | }
65 |
66 | @Test
67 | @SuppressWarnings("ResultOfMethodCallIgnored")
68 | void readInvalidIdTest() {
69 | try {
70 | blockingStub.readBlog(BlogId.getDefaultInstance());
71 | fail("There should be an error in this case");
72 | } catch (StatusRuntimeException e) {
73 | Status status = Status.fromThrowable(e);
74 |
75 | assertEquals(Status.Code.INVALID_ARGUMENT, status.getCode());
76 | assertEquals(BlogServiceImpl.ID_CANNOT_BE_EMPTY, status.getDescription());
77 | }
78 | }
79 |
80 | @Test
81 | @SuppressWarnings("ResultOfMethodCallIgnored")
82 | void readNotFoundTest() {
83 | String id = "579397d20c2dd41b9a8a09eb";
84 |
85 | when(mockCollection.find(any(Bson.class))).thenReturn(iterable);
86 | when(iterable.first()).thenReturn(null);
87 |
88 | try {
89 | blockingStub.readBlog(BlogId.newBuilder().setId(id).build());
90 | fail("There should be an error in this case");
91 | } catch (StatusRuntimeException e) {
92 | Status status = Status.fromThrowable(e);
93 |
94 | assertEquals(Status.Code.NOT_FOUND, status.getCode());
95 | assertNotNull(status.getDescription());
96 | assertTrue(status.getDescription().startsWith(BlogServiceImpl.BLOG_WAS_NOT_FOUND));
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/test/java/blog/server/BlogUpdateTest.java:
--------------------------------------------------------------------------------
1 | package blog.server;
2 |
3 | import com.mongodb.client.FindIterable;
4 | import com.mongodb.client.MongoClient;
5 | import com.mongodb.client.MongoCollection;
6 | import com.mongodb.client.MongoDatabase;
7 | import com.proto.blog.Blog;
8 | import com.proto.blog.BlogServiceGrpc;
9 | import io.grpc.Status;
10 | import io.grpc.StatusRuntimeException;
11 | import org.bson.Document;
12 | import org.bson.conversions.Bson;
13 | import org.bson.types.ObjectId;
14 | import org.junit.jupiter.api.Test;
15 | import org.mockito.Mock;
16 | import org.mockito.MockitoAnnotations;
17 | import utils.ServerTestBase;
18 |
19 | import static org.junit.jupiter.api.Assertions.*;
20 | import static org.mockito.Mockito.*;
21 |
22 | public class BlogUpdateTest extends ServerTestBase<
23 | BlogServiceGrpc.BlogServiceBlockingStub,
24 | BlogServiceGrpc.BlogServiceStub
25 | > {
26 |
27 | @Mock
28 | private MongoClient mockClient;
29 | @Mock
30 | private MongoCollection mockCollection;
31 | @Mock
32 | private MongoDatabase mockDB;
33 | @Mock
34 | private FindIterable iterable;
35 |
36 | BlogUpdateTest() {
37 | MockitoAnnotations.openMocks(this);
38 | when(mockClient.getDatabase(anyString())).thenReturn(mockDB);
39 | when(mockDB.getCollection(anyString())).thenReturn(mockCollection);
40 | addService(new BlogServiceImpl(mockClient));
41 | setBlockingStubInstantiator(BlogServiceGrpc::newBlockingStub);
42 | }
43 |
44 | @Test
45 | void updateTest() {
46 | String id = "579397d20c2dd41b9a8a09eb";
47 | ObjectId oid = new ObjectId(id);
48 | String author = "Clement";
49 | String title = "My Blog";
50 | String content = "This is a cool blog";
51 | Document blog = new Document("_id", oid)
52 | .append("author", author + "_old")
53 | .append("title", title + "_old")
54 | .append("content", content + "_old");
55 |
56 | when(mockCollection.findOneAndUpdate(any(Bson.class), any(Bson.class))).thenReturn(blog);
57 |
58 | assertDoesNotThrow(() -> blockingStub.updateBlog(
59 | Blog.newBuilder()
60 | .setId(id)
61 | .setTitle(title)
62 | .setAuthor(author)
63 | .setContent(content)
64 | .build()
65 | ));
66 | }
67 |
68 | @Test
69 | @SuppressWarnings("ResultOfMethodCallIgnored")
70 | void readInvalidIdTest() {
71 | try {
72 | blockingStub.updateBlog(Blog.newBuilder().build());
73 | fail("There should be an error in this case");
74 | } catch (StatusRuntimeException e) {
75 | Status status = Status.fromThrowable(e);
76 |
77 | assertEquals(Status.Code.INVALID_ARGUMENT, status.getCode());
78 | assertEquals(BlogServiceImpl.ID_CANNOT_BE_EMPTY, status.getDescription());
79 | }
80 | }
81 |
82 | @Test
83 | @SuppressWarnings("ResultOfMethodCallIgnored")
84 | void updateNotFoundTest() {
85 | String id = "579397d20c2dd41b9a8a09eb";
86 |
87 | when(mockCollection.find(any(Bson.class))).thenReturn(iterable);
88 | when(iterable.first()).thenReturn(null);
89 |
90 | try {
91 | blockingStub.updateBlog(Blog.newBuilder().setId(id).build());
92 | fail("There should be an error in this case");
93 | } catch (StatusRuntimeException e) {
94 | Status status = Status.fromThrowable(e);
95 |
96 | assertEquals(Status.Code.NOT_FOUND, status.getCode());
97 | assertNotNull(status.getDescription());
98 | assertTrue(status.getDescription().startsWith(BlogServiceImpl.BLOG_WAS_NOT_FOUND));
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/test/java/calculator/server/CalculatorAvgTest.java:
--------------------------------------------------------------------------------
1 | package calculator.server;
2 |
3 | import com.proto.calculator.AvgRequest;
4 | import com.proto.calculator.AvgResponse;
5 | import com.proto.calculator.CalculatorServiceGrpc;
6 | import io.grpc.stub.StreamObserver;
7 | import org.junit.jupiter.api.Test;
8 | import utils.ServerTestBase;
9 |
10 | import javax.annotation.Nullable;
11 | import java.util.concurrent.CountDownLatch;
12 | import java.util.concurrent.TimeUnit;
13 | import java.util.stream.IntStream;
14 |
15 | import static org.junit.jupiter.api.Assertions.*;
16 |
17 | public class CalculatorAvgTest extends ServerTestBase<
18 | CalculatorServiceGrpc.CalculatorServiceBlockingStub,
19 | CalculatorServiceGrpc.CalculatorServiceStub
20 | > {
21 | private double finalResult;
22 |
23 | @Nullable
24 | private Throwable error = null;
25 |
26 | CalculatorAvgTest() {
27 | addService(new CalculatorServiceImpl());
28 | setAsyncStubInstantiator(CalculatorServiceGrpc::newStub);
29 | }
30 |
31 | @Test
32 | void avgTest() throws InterruptedException {
33 | CountDownLatch latch = new CountDownLatch(1);
34 |
35 | StreamObserver stream = asyncStub.avg(new StreamObserver() {
36 | @Override
37 | public void onNext(AvgResponse response) {
38 | finalResult = response.getResult();
39 | }
40 |
41 | @Override
42 | public void onError(Throwable t) {
43 | error = t;
44 | }
45 |
46 | @Override
47 | public void onCompleted() {
48 | latch.countDown();
49 | }
50 | });
51 |
52 | IntStream.range(1, 11).forEach(number ->
53 | stream.onNext(AvgRequest.newBuilder().setNumber(number).build())
54 | );
55 |
56 | stream.onCompleted();
57 |
58 | boolean reachedZero = latch.await(3, TimeUnit.SECONDS);
59 |
60 | assertTrue(reachedZero);
61 | assertEquals(5.5, finalResult);
62 | assertNull(error);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/test/java/calculator/server/CalculatorMaxTest.java:
--------------------------------------------------------------------------------
1 | package calculator.server;
2 |
3 | import com.proto.calculator.CalculatorServiceGrpc;
4 | import com.proto.calculator.MaxRequest;
5 | import com.proto.calculator.MaxResponse;
6 | import io.grpc.stub.StreamObserver;
7 | import org.junit.jupiter.api.Test;
8 | import utils.ServerTestBase;
9 |
10 | import javax.annotation.Nullable;
11 | import java.util.ArrayList;
12 | import java.util.Collections;
13 | import java.util.List;
14 | import java.util.concurrent.CountDownLatch;
15 | import java.util.concurrent.TimeUnit;
16 |
17 | import static org.junit.jupiter.api.Assertions.*;
18 |
19 | public class CalculatorMaxTest extends ServerTestBase<
20 | CalculatorServiceGrpc.CalculatorServiceBlockingStub,
21 | CalculatorServiceGrpc.CalculatorServiceStub
22 | > {
23 | private final List finalResult = new ArrayList<>();
24 |
25 | @Nullable
26 | private Throwable error = null;
27 |
28 | CalculatorMaxTest() {
29 | addService(new CalculatorServiceImpl());
30 | setAsyncStubInstantiator(CalculatorServiceGrpc::newStub);
31 | }
32 |
33 | @Test
34 | void maxTest() throws InterruptedException {
35 | List numbers = new ArrayList<>();
36 | CountDownLatch latch = new CountDownLatch(1);
37 |
38 | Collections.addAll(numbers, 1, 5, 3, 6, 2, 20);
39 |
40 | StreamObserver stream = asyncStub.max(new StreamObserver() {
41 | @Override
42 | public void onNext(MaxResponse response) {
43 | finalResult.add(response.getMax());
44 | }
45 |
46 | @Override
47 | public void onError(Throwable t) {
48 | error = t;
49 | }
50 |
51 | @Override
52 | public void onCompleted() {
53 | latch.countDown();
54 | }
55 | });
56 |
57 | for (int number : numbers) {
58 | stream.onNext(MaxRequest.newBuilder().setNumber(number).build());
59 | }
60 |
61 | stream.onCompleted();
62 |
63 | boolean reachedZero = latch.await(3, TimeUnit.SECONDS);
64 | List expected = new ArrayList<>();
65 |
66 | Collections.addAll(expected, 1, 5, 6, 20);
67 |
68 | assertTrue(reachedZero);
69 | assertEquals(finalResult, expected);
70 | assertNull(error);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/test/java/calculator/server/CalculatorPrimesTest.java:
--------------------------------------------------------------------------------
1 | package calculator.server;
2 |
3 | import com.proto.calculator.CalculatorServiceGrpc;
4 | import com.proto.calculator.PrimeRequest;
5 | import org.junit.jupiter.api.Test;
6 | import utils.ServerTestBase;
7 |
8 | import java.util.ArrayList;
9 | import java.util.Collections;
10 | import java.util.List;
11 |
12 | import static org.junit.jupiter.api.Assertions.assertEquals;
13 |
14 | public class CalculatorPrimesTest extends ServerTestBase<
15 | CalculatorServiceGrpc.CalculatorServiceBlockingStub,
16 | CalculatorServiceGrpc.CalculatorServiceStub
17 | > {
18 | CalculatorPrimesTest() {
19 | addService(new CalculatorServiceImpl());
20 | setBlockingStubInstantiator(CalculatorServiceGrpc::newBlockingStub);
21 | }
22 |
23 | private final List results = new ArrayList<>();
24 |
25 | @Test
26 | void primesTest() {
27 | blockingStub.primes(PrimeRequest.newBuilder().setNumber(567890).build()).forEachRemaining(prime ->
28 | results.add(prime.getPrimeFactor())
29 | );
30 |
31 | List primes = new ArrayList<>();
32 | Collections.addAll(primes, 2, 5, 109, 521);
33 |
34 | assertEquals(results, primes);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/java/calculator/server/CalculatorSqrtTest.java:
--------------------------------------------------------------------------------
1 | package calculator.server;
2 |
3 | import com.proto.calculator.CalculatorServiceGrpc;
4 | import com.proto.calculator.SqrtRequest;
5 | import com.proto.calculator.SqrtResponse;
6 | import io.grpc.Status;
7 | import io.grpc.StatusRuntimeException;
8 | import org.junit.jupiter.api.Test;
9 | import utils.ServerTestBase;
10 |
11 | import static org.junit.jupiter.api.Assertions.assertEquals;
12 | import static org.junit.jupiter.api.Assertions.fail;
13 |
14 | public class CalculatorSqrtTest extends ServerTestBase<
15 | CalculatorServiceGrpc.CalculatorServiceBlockingStub,
16 | CalculatorServiceGrpc.CalculatorServiceStub
17 | > {
18 |
19 | CalculatorSqrtTest() {
20 | addService(new CalculatorServiceImpl());
21 | setBlockingStubInstantiator(CalculatorServiceGrpc::newBlockingStub);
22 | }
23 |
24 | @Test
25 | void sqrtTest() {
26 | SqrtResponse response = blockingStub.sqrt(SqrtRequest.newBuilder().setNumber(25).build());
27 |
28 | assertEquals(5, response.getResult());
29 | }
30 |
31 | @Test
32 | @SuppressWarnings("ResultOfMethodCallIgnored")
33 | void sqrtErrorTest() {
34 | try {
35 | blockingStub.sqrt(SqrtRequest.newBuilder().setNumber(-1).build());
36 | fail("There should be an error in this case");
37 | } catch (StatusRuntimeException e) {
38 | Status status = Status.fromThrowable(e);
39 |
40 | assertEquals(Status.Code.INVALID_ARGUMENT, status.getCode());
41 | assertEquals("The number being sent cannot be negative\nNumber: -1", status.getDescription());
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/calculator/server/CalculatorSumTest.java:
--------------------------------------------------------------------------------
1 | package calculator.server;
2 |
3 | import com.proto.calculator.CalculatorServiceGrpc;
4 | import com.proto.calculator.SumRequest;
5 | import com.proto.calculator.SumResponse;
6 | import org.junit.jupiter.api.Test;
7 | import utils.ServerTestBase;
8 |
9 | import static org.junit.jupiter.api.Assertions.assertEquals;
10 |
11 | public class CalculatorSumTest extends ServerTestBase<
12 | CalculatorServiceGrpc.CalculatorServiceBlockingStub,
13 | CalculatorServiceGrpc.CalculatorServiceStub
14 | > {
15 |
16 | CalculatorSumTest() {
17 | addService(new CalculatorServiceImpl());
18 | setBlockingStubInstantiator(CalculatorServiceGrpc::newBlockingStub);
19 | }
20 |
21 | @Test
22 | void sumTest() {
23 | SumResponse response = blockingStub.sum(SumRequest.newBuilder().setFirstNumber(1).setSecondNumber(1).build());
24 |
25 | assertEquals(2, response.getResult());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/java/greeting/server/GreetingEveryoneServerTest.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import com.proto.greeting.GreetingRequest;
4 | import com.proto.greeting.GreetingResponse;
5 | import com.proto.greeting.GreetingServiceGrpc;
6 | import io.grpc.stub.StreamObserver;
7 | import org.junit.jupiter.api.Test;
8 | import utils.ServerTestBase;
9 |
10 | import javax.annotation.Nullable;
11 | import java.util.ArrayList;
12 | import java.util.Collections;
13 | import java.util.List;
14 | import java.util.concurrent.CountDownLatch;
15 | import java.util.concurrent.TimeUnit;
16 | import java.util.stream.Collectors;
17 |
18 | import static org.junit.jupiter.api.Assertions.*;
19 |
20 | public class GreetingEveryoneServerTest extends ServerTestBase {
21 |
22 | private final List finalResult = new ArrayList<>();
23 |
24 | @Nullable
25 | private Throwable error = null;
26 |
27 | GreetingEveryoneServerTest() {
28 | addService(new GreetingServiceImpl(new SleeperImpl()));
29 | setAsyncStubInstantiator(GreetingServiceGrpc::newStub);
30 | }
31 |
32 | @Test
33 | void greetEveryoneImplReplyMessage() throws InterruptedException {
34 | List names = new ArrayList<>();
35 | CountDownLatch latch = new CountDownLatch(1);
36 |
37 | Collections.addAll(names, "Clement", "Marie", "Test");
38 |
39 | StreamObserver stream = asyncStub.greetEveryone(new StreamObserver() {
40 | @Override
41 | public void onNext(GreetingResponse response) {
42 | finalResult.add(response.getResult());
43 | }
44 |
45 | @Override
46 | public void onError(Throwable t) {
47 | error = t;
48 | }
49 |
50 | @Override
51 | public void onCompleted() {
52 | latch.countDown();
53 | }
54 | });
55 |
56 | for (String name: names) {
57 | stream.onNext(GreetingRequest.newBuilder().setFirstName(name).build());
58 | }
59 |
60 | stream.onCompleted();
61 |
62 | boolean reachedZero = latch.await(3, TimeUnit.SECONDS);
63 |
64 | assertTrue(reachedZero);
65 | assertEquals(finalResult, names.stream().map(name -> "Hello " + name).collect(Collectors.toList()));
66 | assertNull(error);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/test/java/greeting/server/GreetingManyTimesServerTest.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import com.proto.greeting.GreetingRequest;
4 | import com.proto.greeting.GreetingServiceGrpc;
5 | import org.junit.jupiter.api.Test;
6 | import utils.ServerTestBase;
7 |
8 | import java.util.concurrent.atomic.AtomicInteger;
9 |
10 | import static org.junit.jupiter.api.Assertions.assertEquals;
11 |
12 | public class GreetingManyTimesServerTest extends ServerTestBase {
13 |
14 | GreetingManyTimesServerTest() {
15 | addService(new GreetingServiceImpl(new SleeperImpl()));
16 | setBlockingStubInstantiator(GreetingServiceGrpc::newBlockingStub);
17 | }
18 |
19 | @Test
20 | void greetManyTimesImplReplyMessage() {
21 | AtomicInteger count = new AtomicInteger();
22 |
23 | blockingStub.greetManyTimes(GreetingRequest.newBuilder().setFirstName("Clement").build()).forEachRemaining(response -> {
24 | assertEquals("Hello Clement", response.getResult());
25 | count.incrementAndGet();
26 | });
27 |
28 | assertEquals(count.get(), 10);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/test/java/greeting/server/GreetingServerTest.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import com.proto.greeting.GreetingRequest;
4 | import com.proto.greeting.GreetingResponse;
5 | import com.proto.greeting.GreetingServiceGrpc;
6 | import org.junit.jupiter.api.Test;
7 | import utils.ServerTestBase;
8 |
9 | import static org.junit.jupiter.api.Assertions.assertEquals;
10 |
11 | public class GreetingServerTest extends ServerTestBase {
12 |
13 | GreetingServerTest() {
14 | addService(new GreetingServiceImpl(new SleeperImpl()));
15 | setBlockingStubInstantiator(GreetingServiceGrpc::newBlockingStub);
16 | }
17 |
18 | @Test
19 | void greetImplReplyMessage() {
20 | GreetingResponse response = blockingStub.greet(GreetingRequest.newBuilder().setFirstName("Clement").build());
21 |
22 | assertEquals("Hello Clement", response.getResult());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/test/java/greeting/server/GreetingWithDeadlineTest.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import com.proto.greeting.GreetingRequest;
4 | import com.proto.greeting.GreetingResponse;
5 | import com.proto.greeting.GreetingServiceGrpc;
6 | import io.grpc.Deadline;
7 | import io.grpc.Status;
8 | import io.grpc.StatusRuntimeException;
9 | import org.junit.jupiter.api.Test;
10 | import utils.ServerTestBase;
11 |
12 | import java.util.concurrent.TimeUnit;
13 |
14 | import static org.junit.jupiter.api.Assertions.assertEquals;
15 | import static org.junit.jupiter.api.Assertions.fail;
16 |
17 | public class GreetingWithDeadlineTest extends ServerTestBase<
18 | GreetingServiceGrpc.GreetingServiceBlockingStub,
19 | GreetingServiceGrpc.GreetingServiceStub
20 | > {
21 | GreetingWithDeadlineTest() {
22 | addService(new GreetingServiceImpl(new SleeperImpl()));
23 | setBlockingStubInstantiator(GreetingServiceGrpc::newBlockingStub);
24 | }
25 |
26 | @Test
27 | void greetTest() {
28 | GreetingResponse response = blockingStub.withDeadline(Deadline.after(3, TimeUnit.SECONDS))
29 | .greetWithDeadline(GreetingRequest.newBuilder().setFirstName("Clement").build());
30 |
31 | assertEquals("Hello Clement", response.getResult());
32 | }
33 |
34 | @Test
35 | @SuppressWarnings("ResultOfMethodCallIgnored")
36 | void greetDeadlineExceededTest() {
37 | try {
38 | blockingStub.withDeadline(Deadline.after(100, TimeUnit.MILLISECONDS))
39 | .greetWithDeadline(GreetingRequest.newBuilder().setFirstName("Clement").build());
40 | fail("There should be an error in this case");
41 | } catch (StatusRuntimeException e) {
42 | Status status = Status.fromThrowable(e);
43 |
44 | assertEquals(Status.Code.DEADLINE_EXCEEDED, status.getCode());
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/test/java/greeting/server/GreetingWithDeadlineThrowsTest.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import com.proto.greeting.GreetingRequest;
4 | import com.proto.greeting.GreetingServiceGrpc;
5 | import io.grpc.*;
6 | import io.grpc.inprocess.InProcessChannelBuilder;
7 | import io.grpc.inprocess.InProcessServerBuilder;
8 | import org.junit.After;
9 | import org.junit.jupiter.api.Test;
10 | import utils.Sleeper;
11 |
12 | import java.io.IOException;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | import static org.junit.jupiter.api.Assertions.fail;
16 |
17 | public class GreetingWithDeadlineThrowsTest {
18 |
19 | private static class ThrowingSleeper implements Sleeper {
20 | @Override
21 | public void sleep(long millis) throws InterruptedException {
22 | throw new InterruptedException();
23 | }
24 | }
25 |
26 | private Server server;
27 | private ManagedChannel channel;
28 |
29 | @After
30 | public void after() throws InterruptedException {
31 | if (!server.isShutdown())
32 | server.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
33 |
34 | if (!channel.isShutdown())
35 | channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
36 | }
37 |
38 | @Test
39 | @SuppressWarnings("ResultOfMethodCallIgnored")
40 | void greetThrows() throws IOException {
41 | String serverName = InProcessServerBuilder.generateName();
42 | server = InProcessServerBuilder.forName(serverName)
43 | .directExecutor()
44 | .addService(new GreetingServiceImpl(new ThrowingSleeper()))
45 | .build()
46 | .start();
47 | channel = InProcessChannelBuilder.forName(serverName)
48 | .directExecutor()
49 | .build();
50 | GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel);
51 |
52 | try {
53 | stub.withDeadline(Deadline.after(100, TimeUnit.MILLISECONDS))
54 | .greetWithDeadline(GreetingRequest.newBuilder().setFirstName("Clement").build());
55 | fail("There should be an error in this case");
56 | } catch (RuntimeException e) {
57 | // success
58 | channel.shutdownNow();
59 | server.shutdownNow();
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/test/java/greeting/server/InterceptorTest.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import com.proto.greeting.GreetingRequest;
4 | import com.proto.greeting.GreetingResponse;
5 | import com.proto.greeting.GreetingServiceGrpc;
6 | import greeting.client.AddHeaderInterceptor;
7 | import io.grpc.*;
8 | import io.grpc.inprocess.InProcessChannelBuilder;
9 | import io.grpc.inprocess.InProcessServerBuilder;
10 | import org.junit.jupiter.api.Test;
11 |
12 | import java.io.IOException;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | import static org.junit.jupiter.api.Assertions.assertEquals;
16 | import static org.junit.jupiter.api.Assertions.fail;
17 |
18 | public class InterceptorTest {
19 |
20 | @Test
21 | void interceptPassingTest() throws IOException, InterruptedException {
22 | String serverName = "test";
23 | InProcessServerBuilder builder = InProcessServerBuilder.forName(serverName)
24 | .addService(new GreetingServiceImpl(new SleeperImpl()))
25 | .intercept(new HeaderCheckInterceptor());
26 |
27 | Server server = builder.build();
28 | server.start();
29 |
30 | ManagedChannel channel = InProcessChannelBuilder.forName(serverName)
31 | .directExecutor()
32 | .usePlaintext()
33 | .intercept(new AddHeaderInterceptor())
34 | .build();
35 |
36 | GreetingServiceGrpc.GreetingServiceBlockingStub blockingStub = GreetingServiceGrpc.newBlockingStub(channel);
37 |
38 | GreetingResponse response = blockingStub.greet(GreetingRequest.newBuilder().setFirstName("Clement").build());
39 |
40 | assertEquals("Hello Clement", response.getResult());
41 | if (!server.isShutdown())
42 | server.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
43 |
44 | if (!channel.isShutdown())
45 | channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
46 | }
47 |
48 | @Test
49 | @SuppressWarnings("ResultOfMethodCallIgnored")
50 | void interceptErrorTest() throws IOException, InterruptedException {
51 | String serverName = "test";
52 | InProcessServerBuilder builder = InProcessServerBuilder.forName(serverName)
53 | .addService(new GreetingServiceImpl(new SleeperImpl()))
54 | .intercept(new HeaderCheckInterceptor());
55 |
56 | Server server = builder.build();
57 | server.start();
58 |
59 | ManagedChannel channel = InProcessChannelBuilder.forName(serverName)
60 | .directExecutor()
61 | .usePlaintext()
62 | .build();
63 |
64 | GreetingServiceGrpc.GreetingServiceBlockingStub blockingStub = GreetingServiceGrpc.newBlockingStub(channel);
65 |
66 | try {
67 | blockingStub.greet(GreetingRequest.newBuilder().setFirstName("Clement").build());
68 | fail("There should be an error in this case");
69 | } catch (StatusRuntimeException e) {
70 | Status status = Status.fromThrowable(e);
71 |
72 | assertEquals(Status.Code.CANCELLED, status.getCode());
73 | }
74 |
75 | if (!server.isShutdown())
76 | server.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
77 |
78 | if (!channel.isShutdown())
79 | channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/test/java/greeting/server/LongGreetingServerTest.java:
--------------------------------------------------------------------------------
1 | package greeting.server;
2 |
3 | import com.proto.greeting.GreetingRequest;
4 | import com.proto.greeting.GreetingResponse;
5 | import com.proto.greeting.GreetingServiceGrpc;
6 | import io.grpc.stub.StreamObserver;
7 | import org.junit.jupiter.api.Test;
8 | import utils.ServerTestBase;
9 |
10 | import javax.annotation.Nullable;
11 | import java.util.ArrayList;
12 | import java.util.Collections;
13 | import java.util.List;
14 | import java.util.concurrent.CountDownLatch;
15 | import java.util.concurrent.TimeUnit;
16 |
17 | import static org.junit.jupiter.api.Assertions.*;
18 |
19 | public class LongGreetingServerTest extends ServerTestBase {
20 |
21 | private String finalResult = "";
22 |
23 | @Nullable
24 | private Throwable error = null;
25 |
26 | LongGreetingServerTest() {
27 | addService(new GreetingServiceImpl(new SleeperImpl()));
28 | setAsyncStubInstantiator(GreetingServiceGrpc::newStub);
29 | }
30 |
31 | @Test
32 | void longGreetImplReplyMessage() throws InterruptedException {
33 | List names = new ArrayList<>();
34 | CountDownLatch latch = new CountDownLatch(1);
35 |
36 | Collections.addAll(names, "Clement", "Marie", "Test");
37 |
38 | StreamObserver stream = asyncStub.longGreet(new StreamObserver() {
39 | @Override
40 | public void onNext(GreetingResponse response) {
41 | finalResult = response.getResult();
42 | }
43 |
44 | @Override
45 | public void onError(Throwable t) {
46 | error = t;
47 | }
48 |
49 | @Override
50 | public void onCompleted() {
51 | latch.countDown();
52 | }
53 | });
54 |
55 | for (String name: names) {
56 | stream.onNext(GreetingRequest.newBuilder().setFirstName(name).build());
57 | }
58 |
59 | stream.onCompleted();
60 |
61 | boolean reachedZero = latch.await(3, TimeUnit.SECONDS);
62 |
63 | assertTrue(reachedZero);
64 | assertEquals("Hello Clement!\nHello Marie!\nHello Test!\n", finalResult);
65 | assertNull(error);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/test/java/utils/ClientTestBase.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | import io.grpc.BindableService;
4 | import io.grpc.ManagedChannel;
5 | import io.grpc.Server;
6 | import io.grpc.inprocess.InProcessChannelBuilder;
7 | import io.grpc.inprocess.InProcessServerBuilder;
8 | import io.grpc.stub.AbstractStub;
9 | import org.junit.jupiter.api.AfterEach;
10 |
11 | import java.io.IOException;
12 | import java.util.concurrent.TimeUnit;
13 |
14 | @SuppressWarnings("rawtypes")
15 | public class ClientTestBase {
16 |
17 | private Server server;
18 | private ManagedChannel channel;
19 | private STUB stub;
20 |
21 | @AfterEach
22 | void after() throws InterruptedException {
23 | if (!server.isShutdown())
24 | server.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
25 |
26 | if (!channel.isShutdown())
27 | channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
28 | }
29 |
30 | protected STUB getStub() { return stub; }
31 |
32 | protected void createServerWithService(
33 | BindableService service,
34 | StubInstantiator instantiator
35 | ) throws IOException {
36 | String serverName = InProcessServerBuilder.generateName();
37 | server = InProcessServerBuilder.forName(serverName)
38 | .directExecutor()
39 | .addService(service)
40 | .build()
41 | .start();
42 | channel = InProcessChannelBuilder.forName(serverName)
43 | .directExecutor()
44 | .build();
45 | stub = instantiator.instantiate(channel);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/test/java/utils/ServerTestBase.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | import io.grpc.BindableService;
4 | import io.grpc.ManagedChannel;
5 | import io.grpc.Server;
6 | import io.grpc.inprocess.InProcessChannelBuilder;
7 | import io.grpc.inprocess.InProcessServerBuilder;
8 | import io.grpc.stub.AbstractAsyncStub;
9 | import io.grpc.stub.AbstractBlockingStub;
10 | import org.junit.jupiter.api.AfterEach;
11 | import org.junit.jupiter.api.BeforeEach;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import java.util.concurrent.TimeUnit;
16 |
17 | @SuppressWarnings("rawtypes")
18 | public class ServerTestBase {
19 | private static final String serverName = "test";
20 |
21 | private Server server;
22 | private ManagedChannel channel;
23 | private StubInstantiator blockingStubInstantiator = null;
24 | private StubInstantiator asyncStubInstantiator = null;
25 | protected BLOCKING_STUB blockingStub = null;
26 | protected ASYNC_STUB asyncStub = null;
27 |
28 | private final List services = new ArrayList<>();
29 |
30 | protected void addService(BindableService service) {
31 | this.services.add(service);
32 | }
33 |
34 | protected void setBlockingStubInstantiator(StubInstantiator stub) {
35 | this.blockingStubInstantiator = stub;
36 | }
37 |
38 | protected void setAsyncStubInstantiator(StubInstantiator stub) {
39 | this.asyncStubInstantiator = stub;
40 | }
41 |
42 | @BeforeEach
43 | void before() throws Throwable {
44 | InProcessServerBuilder builder = InProcessServerBuilder.forName(serverName);
45 |
46 | for (BindableService service : services)
47 | builder.addService(service);
48 |
49 | server = builder.build();
50 | server.start();
51 |
52 | channel = InProcessChannelBuilder.forName(serverName)
53 | .directExecutor()
54 | .usePlaintext()
55 | .build();
56 |
57 | if (blockingStubInstantiator != null)
58 | blockingStub = blockingStubInstantiator.instantiate(channel);
59 | if (asyncStubInstantiator != null)
60 | asyncStub = asyncStubInstantiator.instantiate(channel);
61 |
62 | if (asyncStub == null && blockingStub == null)
63 | throw new Throwable("Either blockingStub or asyncStub need to be initialized.");
64 | }
65 |
66 | @AfterEach
67 | void after() throws InterruptedException {
68 | if (!server.isShutdown())
69 | server.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
70 |
71 | if (!channel.isShutdown())
72 | channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/test/java/utils/StubInstantiator.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | import io.grpc.ManagedChannel;
4 | import io.grpc.stub.AbstractStub;
5 |
6 | @SuppressWarnings("rawtypes")
7 | public interface StubInstantiator {
8 | STUB instantiate(ManagedChannel channel);
9 | }
--------------------------------------------------------------------------------
/ssl/README.md:
--------------------------------------------------------------------------------
1 | # SSL
2 |
3 | ## OpenSSL
4 |
5 | Check if you already have OpenSSL installed:
6 |
7 | ```shell
8 | openssl version
9 | ```
10 |
11 | If this gives you an error, please follow instructions [here](https://github.com/openssl/openssl) to install it.
12 |
13 | ## Run
14 |
15 | ```shell
16 | chmod +x ssl.sh
17 | ./ssl.sh
18 | ```
--------------------------------------------------------------------------------
/ssl/ssl.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Output files
3 | # ca.key: Certificate Authority private key file (this shouldn't be shared in real-life)
4 | # ca.crt: Certificate Authority trust certificate (this should be shared with users in real-life)
5 | # server.key: Server private key, password protected (this shouldn't be shared)
6 | # server.csr: Server certificate signing request (this should be shared with the CA owner)
7 | # server.crt: Server certificate signed by the CA (this would be sent back by the CA owner) - keep on server
8 | # server.pem: Conversion of server.key into a format gRPC likes (this shouldn't be shared)
9 |
10 | # Summary
11 | # Private files: ca.key, server.key, server.pem, server.crt
12 | # "Share" files: ca.crt (needed by the client), server.csr (needed by the CA)
13 |
14 | # Changes these CN's to match your hosts in your environment if needed.
15 | SERVER_CN=localhost
16 |
17 | # Step 1: Generate Certificate Authority + Trust Certificate (ca.crt)
18 | openssl genrsa -passout pass:1111 -des3 -out ca.key 4096
19 | openssl req -passin pass:1111 -new -x509 -days 365 -key ca.key -out ca.crt -subj "/CN=ca"
20 |
21 | # Step 2: Generate the Server Private Key (server.key)
22 | openssl genrsa -passout pass:1111 -des3 -out server.key 4096
23 |
24 | # Step 3: Get a certificate signing request from the CA (server.csr)
25 | openssl req -passin pass:1111 -new -key server.key -out server.csr -subj "/CN=${SERVER_CN}"
26 |
27 | # Step 4: Sign the certificate with the CA we created (it's called self signing) - server.crt
28 | openssl x509 -req -extfile <(printf "subjectAltName=DNS:%s" ${SERVER_CN}) -passin pass:1111 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
29 |
30 | # Step 5: Convert the server certificate to .pem format (server.pem) - usable by gRPC
31 | openssl pkcs8 -topk8 -nocrypt -passin pass:1111 -in server.key -out server.pem
--------------------------------------------------------------------------------