Squashed 'third_party/flatbuffers/' content from commit acc9990ab
Change-Id: I48550d40d78fea996ebe74e9723a5d1f910de491
git-subtree-dir: third_party/flatbuffers
git-subtree-split: acc9990abd2206491480291b0f85f925110102ea
diff --git a/grpc/tests/JavaGrpcTest.java b/grpc/tests/JavaGrpcTest.java
new file mode 100644
index 0000000..98a67b5
--- /dev/null
+++ b/grpc/tests/JavaGrpcTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import MyGame.Example.Monster;
+import MyGame.Example.MonsterStorageGrpc;
+import MyGame.Example.Stat;
+import com.google.flatbuffers.FlatBufferBuilder;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import io.grpc.stub.StreamObserver;
+import org.junit.Assert;
+
+import java.io.IOException;
+import java.lang.InterruptedException;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.CountDownLatch;
+
+
+/**
+ * Demonstrates basic client-server interaction using grpc-java over netty.
+ */
+public class JavaGrpcTest {
+ static final String BIG_MONSTER_NAME = "Cyberdemon";
+ static final short nestedMonsterHp = 600;
+ static final short nestedMonsterMana = 1024;
+ static final int numStreamedMsgs = 10;
+ static final int timeoutMs = 3000;
+ static Server server;
+ static ManagedChannel channel;
+ static MonsterStorageGrpc.MonsterStorageBlockingStub blockingStub;
+ static MonsterStorageGrpc.MonsterStorageStub asyncStub;
+
+ static class MyService extends MonsterStorageGrpc.MonsterStorageImplBase {
+ @Override
+ public void store(Monster request, io.grpc.stub.StreamObserver<Stat> responseObserver) {
+ Assert.assertEquals(request.name(), BIG_MONSTER_NAME);
+ Assert.assertEquals(request.hp(), nestedMonsterHp);
+ Assert.assertEquals(request.mana(), nestedMonsterMana);
+ System.out.println("Received store request from " + request.name());
+ // Create a response from the incoming request name.
+ Stat stat = GameFactory.createStat("Hello " + request.name(), 100, 10);
+ responseObserver.onNext(stat);
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void retrieve(Stat request, io.grpc.stub.StreamObserver<Monster> responseObserver) {
+ // Create 10 monsters for streaming response.
+ for (int i=0; i<numStreamedMsgs; i++) {
+ Monster monster = GameFactory.createMonsterFromStat(request, i);
+ responseObserver.onNext(monster);
+ }
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public StreamObserver<Monster> getMaxHitPoint(final StreamObserver<Stat> responseObserver) {
+ return computeMinMax(responseObserver, false);
+ }
+
+ @Override
+ public StreamObserver<Monster> getMinMaxHitPoints(final StreamObserver<Stat> responseObserver) {
+ return computeMinMax(responseObserver, true);
+ }
+
+ private StreamObserver<Monster> computeMinMax(final StreamObserver<Stat> responseObserver, final boolean includeMin) {
+ final AtomicInteger maxHp = new AtomicInteger(Integer.MIN_VALUE);
+ final AtomicReference<String> maxHpMonsterName = new AtomicReference<String>();
+ final AtomicInteger maxHpCount = new AtomicInteger();
+
+ final AtomicInteger minHp = new AtomicInteger(Integer.MAX_VALUE);
+ final AtomicReference<String> minHpMonsterName = new AtomicReference<String>();
+ final AtomicInteger minHpCount = new AtomicInteger();
+
+ return new StreamObserver<Monster>() {
+ public void onNext(Monster monster) {
+ if (monster.hp() > maxHp.get()) {
+ // Found a monster of higher hit points.
+ maxHp.set(monster.hp());
+ maxHpMonsterName.set(monster.name());
+ maxHpCount.set(1);
+ }
+ else if (monster.hp() == maxHp.get()) {
+ // Count how many times we saw a monster of current max hit points.
+ maxHpCount.getAndIncrement();
+ }
+
+ if (monster.hp() < minHp.get()) {
+ // Found a monster of a lower hit points.
+ minHp.set(monster.hp());
+ minHpMonsterName.set(monster.name());
+ minHpCount.set(1);
+ }
+ else if (monster.hp() == minHp.get()) {
+ // Count how many times we saw a monster of current min hit points.
+ minHpCount.getAndIncrement();
+ }
+ }
+ public void onCompleted() {
+ Stat maxHpStat = GameFactory.createStat(maxHpMonsterName.get(), maxHp.get(), maxHpCount.get());
+ // Send max hit points first.
+ responseObserver.onNext(maxHpStat);
+ if (includeMin) {
+ // Send min hit points.
+ Stat minHpStat = GameFactory.createStat(minHpMonsterName.get(), minHp.get(), minHpCount.get());
+ responseObserver.onNext(minHpStat);
+ }
+ responseObserver.onCompleted();
+ }
+ public void onError(Throwable t) {
+ // Not expected
+ Assert.fail();
+ };
+ };
+ }
+ }
+
+ @org.junit.BeforeClass
+ public static void startServer() throws IOException {
+ server = ServerBuilder.forPort(0).addService(new MyService()).build().start();
+ int port = server.getPort();
+ channel = ManagedChannelBuilder.forAddress("localhost", port)
+ // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
+ // needing certificates.
+ .usePlaintext(true)
+ .directExecutor()
+ .build();
+ blockingStub = MonsterStorageGrpc.newBlockingStub(channel);
+ asyncStub = MonsterStorageGrpc.newStub(channel);
+ }
+
+ @org.junit.Test
+ public void testUnary() throws IOException {
+ Monster monsterRequest = GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana);
+ Stat stat = blockingStub.store(monsterRequest);
+ Assert.assertEquals(stat.id(), "Hello " + BIG_MONSTER_NAME);
+ System.out.println("Received stat response from service: " + stat.id());
+ }
+
+ @org.junit.Test
+ public void testServerStreaming() throws IOException {
+ Monster monsterRequest = GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana);
+ Stat stat = blockingStub.store(monsterRequest);
+ Iterator<Monster> iterator = blockingStub.retrieve(stat);
+ int counter = 0;
+ while(iterator.hasNext()) {
+ Monster m = iterator.next();
+ System.out.println("Received monster " + m.name());
+ counter ++;
+ }
+ Assert.assertEquals(counter, numStreamedMsgs);
+ System.out.println("FlatBuffers GRPC client/server test: completed successfully");
+ }
+
+ @org.junit.Test
+ public void testClientStreaming() throws IOException, InterruptedException {
+ final AtomicReference<Stat> maxHitStat = new AtomicReference<Stat>();
+ final CountDownLatch streamAlive = new CountDownLatch(1);
+
+ StreamObserver<Stat> statObserver = new StreamObserver<Stat>() {
+ public void onCompleted() {
+ streamAlive.countDown();
+ }
+ public void onError(Throwable ex) { }
+ public void onNext(Stat stat) {
+ maxHitStat.set(stat);
+ }
+ };
+ StreamObserver<Monster> monsterStream = asyncStub.getMaxHitPoint(statObserver);
+ short count = 10;
+ for (short i = 0;i < count; ++i) {
+ Monster monster = GameFactory.createMonster(BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana);
+ monsterStream.onNext(monster);
+ }
+ monsterStream.onCompleted();
+ // Wait a little bit for the server to send the stats of the monster with the max hit-points.
+ streamAlive.await(timeoutMs, TimeUnit.MILLISECONDS);
+ Assert.assertEquals(maxHitStat.get().id(), BIG_MONSTER_NAME + (count - 1));
+ Assert.assertEquals(maxHitStat.get().val(), nestedMonsterHp * (count - 1));
+ Assert.assertEquals(maxHitStat.get().count(), 1);
+ }
+
+ @org.junit.Test
+ public void testBiDiStreaming() throws IOException, InterruptedException {
+ final AtomicReference<Stat> maxHitStat = new AtomicReference<Stat>();
+ final AtomicReference<Stat> minHitStat = new AtomicReference<Stat>();
+ final CountDownLatch streamAlive = new CountDownLatch(1);
+
+ StreamObserver<Stat> statObserver = new StreamObserver<Stat>() {
+ public void onCompleted() {
+ streamAlive.countDown();
+ }
+ public void onError(Throwable ex) { }
+ public void onNext(Stat stat) {
+ // We expect the server to send the max stat first and then the min stat.
+ if (maxHitStat.get() == null) {
+ maxHitStat.set(stat);
+ }
+ else {
+ minHitStat.set(stat);
+ }
+ }
+ };
+ StreamObserver<Monster> monsterStream = asyncStub.getMinMaxHitPoints(statObserver);
+ short count = 10;
+ for (short i = 0;i < count; ++i) {
+ Monster monster = GameFactory.createMonster(BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana);
+ monsterStream.onNext(monster);
+ }
+ monsterStream.onCompleted();
+
+ // Wait a little bit for the server to send the stats of the monster with the max and min hit-points.
+ streamAlive.await(timeoutMs, TimeUnit.MILLISECONDS);
+
+ Assert.assertEquals(maxHitStat.get().id(), BIG_MONSTER_NAME + (count - 1));
+ Assert.assertEquals(maxHitStat.get().val(), nestedMonsterHp * (count - 1));
+ Assert.assertEquals(maxHitStat.get().count(), 1);
+
+ Assert.assertEquals(minHitStat.get().id(), BIG_MONSTER_NAME + 0);
+ Assert.assertEquals(minHitStat.get().val(), nestedMonsterHp * 0);
+ Assert.assertEquals(minHitStat.get().count(), 1);
+ }
+}