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/GameFactory.java b/grpc/tests/GameFactory.java
new file mode 100644
index 0000000..520ae39
--- /dev/null
+++ b/grpc/tests/GameFactory.java
@@ -0,0 +1,42 @@
+import java.nio.ByteBuffer;
+import MyGame.Example.Monster;
+import MyGame.Example.Stat;
+import com.google.flatbuffers.FlatBufferBuilder;
+
+class GameFactory {
+  public static Monster createMonster(String monsterName, short nestedMonsterHp, short nestedMonsterMana) {
+    FlatBufferBuilder builder = new FlatBufferBuilder();
+
+    int name_offset = builder.createString(monsterName);
+    Monster.startMonster(builder);
+    Monster.addName(builder, name_offset);
+    Monster.addHp(builder, nestedMonsterHp);
+    Monster.addMana(builder, nestedMonsterMana);
+    int monster_offset = Monster.endMonster(builder);
+    Monster.finishMonsterBuffer(builder, monster_offset);
+
+    ByteBuffer buffer = builder.dataBuffer();
+    Monster monster = Monster.getRootAsMonster(buffer);
+    return monster;
+  }
+
+  public static Monster createMonsterFromStat(Stat stat, int seqNo) {
+    FlatBufferBuilder builder = new FlatBufferBuilder();
+    int name_offset = builder.createString(stat.id() + " No." + seqNo);
+    Monster.startMonster(builder);
+    Monster.addName(builder, name_offset);
+    int monster_offset = Monster.endMonster(builder);
+    Monster.finishMonsterBuffer(builder, monster_offset);
+    Monster monster = Monster.getRootAsMonster(builder.dataBuffer());
+    return monster;
+  }
+
+  public static Stat createStat(String greeting, long val, int count) { 
+    FlatBufferBuilder builder = new FlatBufferBuilder();
+    int statOffset = Stat.createStat(builder, builder.createString(greeting), val, count);
+    builder.finish(statOffset);
+    Stat stat = Stat.getRootAsStat(builder.dataBuffer());
+    return stat;
+  }
+
+}
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);
+    }
+}
diff --git a/grpc/tests/go_test.go b/grpc/tests/go_test.go
new file mode 100644
index 0000000..288036b
--- /dev/null
+++ b/grpc/tests/go_test.go
@@ -0,0 +1,93 @@
+package testing
+
+import (
+	"../../tests/MyGame/Example"
+
+	"context"
+	"net"
+	"testing"
+
+	"google.golang.org/grpc"
+)
+
+type server struct{}
+
+// test used to send and receive in grpc methods
+var test = "Flatbuffers"
+var addr = "0.0.0.0:50051"
+
+// gRPC server store method
+func (s *server) Store(context context.Context, in *Example.Monster) (*flatbuffers.Builder, error) {
+	b := flatbuffers.NewBuilder(0)
+	i := b.CreateString(test)
+	Example.StatStart(b)
+	Example.StatAddId(b, i)
+	b.Finish(Example.StatEnd(b))
+	return b, nil
+
+}
+
+// gRPC server retrieve method
+func (s *server) Retrieve(context context.Context, in *Example.Stat) (*flatbuffers.Builder, error) {
+	b := flatbuffers.NewBuilder(0)
+	i := b.CreateString(test)
+	Example.MonsterStart(b)
+	Example.MonsterAddName(b, i)
+	b.Finish(Example.MonsterEnd(b))
+	return b, nil
+}
+
+func StoreClient(c Example.MonsterStorageClient, t *testing.T) {
+	b := flatbuffers.NewBuilder(0)
+	i := b.CreateString(test)
+	Example.MonsterStart(b)
+	Example.MonsterAddName(b, i)
+	b.Finish(Example.MonsterEnd(b))
+	out, err := c.Store(context.Background(), b)
+	if err != nil {
+		t.Fatalf("Store client failed: %v", err)
+	}
+	if string(out.Id()) != test {
+		t.Errorf("StoreClient failed: expected=%s, got=%s\n", test, out.Id())
+		t.Fail()
+	}
+}
+
+func RetrieveClient(c Example.MonsterStorageClient, t *testing.T) {
+	b := flatbuffers.NewBuilder(0)
+	i := b.CreateString(test)
+	Example.StatStart(b)
+	Example.StatAddId(b, i)
+	b.Finish(Example.StatEnd(b))
+	out, err := c.Retrieve(context.Background(), b)
+	if err != nil {
+		t.Fatalf("Retrieve client failed: %v", err)
+	}
+	if string(out.Name()) != test {
+		t.Errorf("RetrieveClient failed: expected=%s, got=%s\n", test, out.Name())
+		t.Fail()
+	}
+}
+
+func TestGRPC(t *testing.T) {
+	lis, err := net.Listen("tcp", addr)
+	if err != nil {
+		t.Fatalf("Failed to listen: %v", err)
+	}
+	ser := grpc.NewServer(grpc.CustomCodec(flatbuffers.FlatbuffersCodec{}))
+	Example.RegisterMonsterStorageServer(ser, &server{})
+	go func() {
+		if err := ser.Serve(lis); err != nil {
+			t.Fatalf("Failed to serve: %v", err)
+			t.FailNow()
+		}
+	}()
+	conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithCodec(flatbuffers.FlatbuffersCodec{}))
+	if err != nil {
+		t.Fatalf("Failed to connect: %v", err)
+	}
+	defer conn.Close()
+	client := Example.NewMonsterStorageClient(conn)
+	StoreClient(client, t)
+	RetrieveClient(client, t)
+}
diff --git a/grpc/tests/grpctest.cpp b/grpc/tests/grpctest.cpp
new file mode 100644
index 0000000..7e5c6e6
--- /dev/null
+++ b/grpc/tests/grpctest.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+#include <thread>
+
+#include <grpc++/grpc++.h>
+
+#include "monster_test.grpc.fb.h"
+#include "monster_test_generated.h"
+#include "test_assert.h"
+
+using namespace MyGame::Example;
+using flatbuffers::grpc::MessageBuilder;
+using flatbuffers::FlatBufferBuilder;
+
+void message_builder_tests();
+
+// The callback implementation of our server, that derives from the generated
+// code. It implements all rpcs specified in the FlatBuffers schema.
+class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
+  virtual ::grpc::Status Store(
+      ::grpc::ServerContext *context,
+      const flatbuffers::grpc::Message<Monster> *request,
+      flatbuffers::grpc::Message<Stat> *response) override {
+    // Create a response from the incoming request name.
+    fbb_.Clear();
+    auto stat_offset = CreateStat(
+        fbb_, fbb_.CreateString("Hello, " + request->GetRoot()->name()->str()));
+    fbb_.Finish(stat_offset);
+    // Transfer ownership of the message to gRPC
+    *response = fbb_.ReleaseMessage<Stat>();
+    return grpc::Status::OK;
+  }
+  virtual ::grpc::Status Retrieve(
+      ::grpc::ServerContext *context,
+      const flatbuffers::grpc::Message<Stat> *request,
+      ::grpc::ServerWriter<flatbuffers::grpc::Message<Monster>> *writer)
+      override {
+    for (int i = 0; i < 5; i++) {
+      fbb_.Clear();
+      // Create 5 monsters for resposne.
+      auto monster_offset =
+          CreateMonster(fbb_, 0, 0, 0,
+                        fbb_.CreateString(request->GetRoot()->id()->str() +
+                                          " No." + std::to_string(i)));
+      fbb_.Finish(monster_offset);
+
+      flatbuffers::grpc::Message<Monster> monster =
+          fbb_.ReleaseMessage<Monster>();
+
+      // Send monster to client using streaming.
+      writer->Write(monster);
+    }
+    return grpc::Status::OK;
+  }
+
+ private:
+  flatbuffers::grpc::MessageBuilder fbb_;
+};
+
+// Track the server instance, so we can terminate it later.
+grpc::Server *server_instance = nullptr;
+// Mutex to protec this variable.
+std::mutex wait_for_server;
+std::condition_variable server_instance_cv;
+
+// This function implements the server thread.
+void RunServer() {
+  auto server_address = "0.0.0.0:50051";
+  // Callback interface we implemented above.
+  ServiceImpl service;
+  grpc::ServerBuilder builder;
+  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+  builder.RegisterService(&service);
+
+  // Start the server. Lock to change the variable we're changing.
+  wait_for_server.lock();
+  server_instance = builder.BuildAndStart().release();
+  wait_for_server.unlock();
+  server_instance_cv.notify_one();
+
+  std::cout << "Server listening on " << server_address << std::endl;
+  // This will block the thread and serve requests.
+  server_instance->Wait();
+}
+
+template <class Builder>
+void StoreRPC(MonsterStorage::Stub *stub) {
+  Builder fbb;
+  grpc::ClientContext context;
+  // Build a request with the name set.
+  auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
+  MessageBuilder mb(std::move(fbb));
+  mb.Finish(monster_offset);
+  auto request = mb.ReleaseMessage<Monster>();
+  flatbuffers::grpc::Message<Stat> response;
+
+  // The actual RPC.
+  auto status = stub->Store(&context, request, &response);
+
+  if (status.ok()) {
+    auto resp = response.GetRoot()->id();
+    std::cout << "RPC response: " << resp->str() << std::endl;
+  } else {
+    std::cout << "RPC failed" << std::endl;
+  }
+}
+
+template <class Builder>
+void RetrieveRPC(MonsterStorage::Stub *stub) {
+  Builder fbb;
+  grpc::ClientContext context;
+  fbb.Clear();
+  auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
+  fbb.Finish(stat_offset);
+  auto request = MessageBuilder(std::move(fbb)).ReleaseMessage<Stat>();
+
+  flatbuffers::grpc::Message<Monster> response;
+  auto stream = stub->Retrieve(&context, request);
+  while (stream->Read(&response)) {
+    auto resp = response.GetRoot()->name();
+    std::cout << "RPC Streaming response: " << resp->str() << std::endl;
+  }
+}
+
+int grpc_server_test() {
+  // Launch server.
+  std::thread server_thread(RunServer);
+
+  // wait for server to spin up.
+  std::unique_lock<std::mutex> lock(wait_for_server);
+  while (!server_instance) server_instance_cv.wait(lock);
+
+  // Now connect the client.
+  auto channel = grpc::CreateChannel("localhost:50051",
+                                     grpc::InsecureChannelCredentials());
+  auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
+
+  StoreRPC<MessageBuilder>(stub.get());
+  StoreRPC<FlatBufferBuilder>(stub.get());
+
+  RetrieveRPC<MessageBuilder>(stub.get());
+  RetrieveRPC<FlatBufferBuilder>(stub.get());
+
+
+#if !FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
+  {
+    // Test that an invalid request errors out correctly
+    grpc::ClientContext context;
+    flatbuffers::grpc::Message<Monster> request;  // simulate invalid message
+    flatbuffers::grpc::Message<Stat> response;
+    auto status = stub->Store(&context, request, &response);
+    // The rpc status should be INTERNAL to indicate a verification error. This
+    // matches the protobuf gRPC status code for an unparseable message.
+    assert(!status.ok());
+    assert(status.error_code() == ::grpc::StatusCode::INTERNAL);
+    assert(strcmp(status.error_message().c_str(),
+                  "Message verification failed") == 0);
+  }
+#endif
+
+  server_instance->Shutdown();
+
+  server_thread.join();
+
+  delete server_instance;
+
+  return 0;
+}
+
+int main(int /*argc*/, const char * /*argv*/ []) {
+  message_builder_tests();
+  grpc_server_test();
+
+  if (!testing_fails) {
+    TEST_OUTPUT_LINE("ALL TESTS PASSED");
+    return 0;
+  } else {
+    TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
+    return 1;
+  }
+}
+
diff --git a/grpc/tests/java-grpc-test.sh b/grpc/tests/java-grpc-test.sh
new file mode 100755
index 0000000..ec42960
--- /dev/null
+++ b/grpc/tests/java-grpc-test.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# NOTE: make sure `mvn install` in /gprc is executed before running this test
+mvn test
diff --git a/grpc/tests/message_builder_test.cpp b/grpc/tests/message_builder_test.cpp
new file mode 100644
index 0000000..36f5bc2
--- /dev/null
+++ b/grpc/tests/message_builder_test.cpp
@@ -0,0 +1,340 @@
+#include "flatbuffers/grpc.h"
+#include "monster_test_generated.h"
+#include "test_assert.h"
+#include "test_builder.h"
+
+using MyGame::Example::Vec3;
+using MyGame::Example::CreateStat;
+using MyGame::Example::Any_NONE;
+
+bool verify(flatbuffers::grpc::Message<Monster> &msg, const std::string &expected_name, Color color) {
+  const Monster *monster = msg.GetRoot();
+  return (monster->name()->str() == expected_name) && (monster->color() == color);
+}
+
+bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb, const std::string &expected_name, Color color) {
+  flatbuffers::grpc::Message<Monster> msg = mbb.ReleaseMessage<Monster>();
+  const Monster *monster = msg.GetRoot();
+  return (monster->name()->str() == expected_name) && (monster->color() == color);
+}
+
+void builder_move_assign_after_releaseraw_test(flatbuffers::grpc::MessageBuilder dst) {
+  auto root_offset1 = populate1(dst);
+  dst.Finish(root_offset1);
+  size_t size, offset;
+  grpc_slice slice;
+  dst.ReleaseRaw(size, offset, slice);
+  flatbuffers::FlatBufferBuilder src;
+  auto root_offset2 = populate2(src);
+  src.Finish(root_offset2);
+  auto src_size = src.GetSize();
+  // Move into a released builder.
+  dst = std::move(src);
+  TEST_EQ(dst.GetSize(), src_size);
+  TEST_ASSERT(release_n_verify(dst, m2_name, m2_color));
+  TEST_EQ(src.GetSize(), 0);
+  grpc_slice_unref(slice);
+}
+
+template <class SrcBuilder>
+struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder, SrcBuilder> {
+  static void builder_reusable_after_release_message_test(TestSelector selector) {
+    if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE)) {
+      return;
+    }
+
+    flatbuffers::grpc::MessageBuilder mb;
+    std::vector<flatbuffers::grpc::Message<Monster>> buffers;
+    for (int i = 0; i < 5; ++i) {
+      auto root_offset1 = populate1(mb);
+      mb.Finish(root_offset1);
+      buffers.push_back(mb.ReleaseMessage<Monster>());
+      TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
+    }
+  }
+
+  static void builder_reusable_after_release_test(TestSelector selector) {
+    if (!selector.count(REUSABLE_AFTER_RELEASE)) {
+      return;
+    }
+
+    // FIXME: Populate-Release loop fails assert(GRPC_SLICE_IS_EMPTY(slice_)) in SliceAllocator::allocate
+    // in the second iteration.
+
+    flatbuffers::grpc::MessageBuilder mb;
+    std::vector<flatbuffers::DetachedBuffer> buffers;
+    for (int i = 0; i < 2; ++i) {
+      auto root_offset1 = populate1(mb);
+      mb.Finish(root_offset1);
+      buffers.push_back(mb.Release());
+      TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
+    }
+  }
+
+  static void builder_reusable_after_releaseraw_test(TestSelector selector) {
+    if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) {
+      return;
+    }
+
+    flatbuffers::grpc::MessageBuilder mb;
+    for (int i = 0; i < 5; ++i) {
+      auto root_offset1 = populate1(mb);
+      mb.Finish(root_offset1);
+      size_t size, offset;
+      grpc_slice slice;
+      const uint8_t *buf = mb.ReleaseRaw(size, offset, slice);
+      TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
+      grpc_slice_unref(slice);
+    }
+  }
+
+  static void builder_reusable_after_release_and_move_assign_test(TestSelector selector) {
+    if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) {
+      return;
+    }
+
+    // FIXME: Release-move_assign loop fails assert(p == GRPC_SLICE_START_PTR(slice_))
+    // in DetachedBuffer destructor after all the iterations
+
+    flatbuffers::grpc::MessageBuilder dst;
+    std::vector<flatbuffers::DetachedBuffer> buffers;
+
+    for (int i = 0; i < 2; ++i) {
+      auto root_offset1 = populate1(dst);
+      dst.Finish(root_offset1);
+      buffers.push_back(dst.Release());
+      TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
+
+      // bring dst back to life.
+      SrcBuilder src;
+      dst = std::move(src);
+      TEST_EQ_FUNC(dst.GetSize(), 0);
+      TEST_EQ_FUNC(src.GetSize(), 0);
+    }
+  }
+
+  static void builder_reusable_after_release_message_and_move_assign_test(TestSelector selector) {
+    if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN)) {
+      return;
+    }
+
+    flatbuffers::grpc::MessageBuilder dst;
+    std::vector<flatbuffers::grpc::Message<Monster>> buffers;
+
+    for (int i = 0; i < 5; ++i) {
+      auto root_offset1 = populate1(dst);
+      dst.Finish(root_offset1);
+      buffers.push_back(dst.ReleaseMessage<Monster>());
+      TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
+
+      // bring dst back to life.
+      SrcBuilder src;
+      dst = std::move(src);
+      TEST_EQ_FUNC(dst.GetSize(), 0);
+      TEST_EQ_FUNC(src.GetSize(), 0);
+    }
+  }
+
+  static void builder_reusable_after_releaseraw_and_move_assign_test(TestSelector selector) {
+    if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) {
+      return;
+    }
+
+    flatbuffers::grpc::MessageBuilder dst;
+    for (int i = 0; i < 5; ++i) {
+      auto root_offset1 = populate1(dst);
+      dst.Finish(root_offset1);
+      size_t size, offset;
+      grpc_slice slice = grpc_empty_slice();
+      const uint8_t *buf = dst.ReleaseRaw(size, offset, slice);
+      TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
+      grpc_slice_unref(slice);
+
+      SrcBuilder src;
+      dst = std::move(src);
+      TEST_EQ_FUNC(dst.GetSize(), 0);
+      TEST_EQ_FUNC(src.GetSize(), 0);
+    }
+  }
+
+  static void run_tests(TestSelector selector) {
+    builder_reusable_after_release_test(selector);
+    builder_reusable_after_release_message_test(selector);
+    builder_reusable_after_releaseraw_test(selector);
+    builder_reusable_after_release_and_move_assign_test(selector);
+    builder_reusable_after_releaseraw_and_move_assign_test(selector);
+    builder_reusable_after_release_message_and_move_assign_test(selector);
+  }
+};
+
+void slice_allocator_tests() {
+  // move-construct no-delete test
+  {
+    size_t size = 2048;
+    flatbuffers::grpc::SliceAllocator sa1;
+    uint8_t *buf = sa1.allocate(size);
+    TEST_ASSERT_FUNC(buf != 0);
+    buf[0] = 100;
+    buf[size-1] = 200;
+    flatbuffers::grpc::SliceAllocator sa2(std::move(sa1));
+    // buf should not be deleted after move-construct
+    TEST_EQ_FUNC(buf[0], 100);
+    TEST_EQ_FUNC(buf[size-1], 200);
+    // buf is freed here
+  }
+
+  // move-assign test
+  {
+    flatbuffers::grpc::SliceAllocator sa1, sa2;
+    uint8_t *buf = sa1.allocate(2048);
+    sa1 = std::move(sa2);
+    // sa1 deletes previously allocated memory in move-assign.
+    // So buf is no longer usable here.
+    TEST_ASSERT_FUNC(buf != 0);
+  }
+}
+
+/// This function does not populate exactly the first half of the table. But it could.
+void populate_first_half(MyGame::Example::MonsterBuilder &wrapper, flatbuffers::Offset<flatbuffers::String> name_offset) {
+  wrapper.add_name(name_offset);
+  wrapper.add_color(m1_color);
+}
+
+/// This function does not populate exactly the second half of the table. But it could.
+void populate_second_half(MyGame::Example::MonsterBuilder &wrapper) {
+  wrapper.add_hp(77);
+  wrapper.add_mana(88);
+  Vec3 vec3;
+  wrapper.add_pos(&vec3);
+}
+
+/// This function is a hack to update the FlatBufferBuilder reference (fbb_) in the MonsterBuilder object.
+/// This function will break if fbb_ is not the first member in MonsterBuilder. In that case, some offset must be added.
+/// This function is used exclusively for testing correctness of move operations between FlatBufferBuilders.
+/// If MonsterBuilder had a fbb_ pointer, this hack would be unnecessary. That involves a code-generator change though.
+void test_only_hack_update_fbb_reference(MyGame::Example::MonsterBuilder &monsterBuilder,
+                                         flatbuffers::grpc::MessageBuilder &mb) {
+  *reinterpret_cast<flatbuffers::FlatBufferBuilder **>(&monsterBuilder) = &mb;
+}
+
+/// This test validates correctness of move conversion of FlatBufferBuilder to a MessageBuilder DURING
+/// a table construction. Half of the table is constructed using FlatBufferBuilder and the other half
+/// of the table is constructed using a MessageBuilder.
+void builder_move_ctor_conversion_before_finish_half_n_half_table_test() {
+  for (size_t initial_size = 4 ; initial_size <= 2048; initial_size *= 2) {
+    flatbuffers::FlatBufferBuilder fbb(initial_size);
+    auto name_offset = fbb.CreateString(m1_name);
+    MyGame::Example::MonsterBuilder monsterBuilder(fbb);     // starts a table in FlatBufferBuilder
+    populate_first_half(monsterBuilder, name_offset);
+    flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
+    test_only_hack_update_fbb_reference(monsterBuilder, mb); // hack
+    populate_second_half(monsterBuilder);
+    mb.Finish(monsterBuilder.Finish());                      // ends the table in MessageBuilder
+    TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+    TEST_EQ_FUNC(fbb.GetSize(), 0);
+  }
+}
+
+/// This test populates a COMPLETE inner table before move conversion and later populates more members in the outer table.
+void builder_move_ctor_conversion_before_finish_test() {
+  for (size_t initial_size = 4 ; initial_size <= 2048; initial_size *= 2) {
+    flatbuffers::FlatBufferBuilder fbb(initial_size);
+    auto stat_offset = CreateStat(fbb, fbb.CreateString("SomeId"), 0, 0);
+    flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
+    auto monster_offset = CreateMonster(mb, 0, 150, 100, mb.CreateString(m1_name), 0, m1_color, Any_NONE, 0, 0, 0, 0, 0, 0, stat_offset);
+    mb.Finish(monster_offset);
+    TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+    TEST_EQ_FUNC(fbb.GetSize(), 0);
+  }
+}
+
+/// This test validates correctness of move conversion of FlatBufferBuilder to a MessageBuilder DURING
+/// a table construction. Half of the table is constructed using FlatBufferBuilder and the other half
+/// of the table is constructed using a MessageBuilder.
+void builder_move_assign_conversion_before_finish_half_n_half_table_test() {
+  flatbuffers::FlatBufferBuilder fbb;
+  flatbuffers::grpc::MessageBuilder mb;
+
+  for (int i = 0;i < 5; ++i) {
+    flatbuffers::FlatBufferBuilder fbb;
+    auto name_offset = fbb.CreateString(m1_name);
+    MyGame::Example::MonsterBuilder monsterBuilder(fbb);     // starts a table in FlatBufferBuilder
+    populate_first_half(monsterBuilder, name_offset);
+    mb = std::move(fbb);
+    test_only_hack_update_fbb_reference(monsterBuilder, mb); // hack
+    populate_second_half(monsterBuilder);
+    mb.Finish(monsterBuilder.Finish());                      // ends the table in MessageBuilder
+    TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+    TEST_EQ_FUNC(fbb.GetSize(), 0);
+  }
+}
+
+/// This test populates a COMPLETE inner table before move conversion and later populates more members in the outer table.
+void builder_move_assign_conversion_before_finish_test() {
+  flatbuffers::FlatBufferBuilder fbb;
+  flatbuffers::grpc::MessageBuilder mb;
+
+  for (int i = 0;i < 5; ++i) {
+    auto stat_offset = CreateStat(fbb, fbb.CreateString("SomeId"), 0, 0);
+    mb = std::move(fbb);
+    auto monster_offset = CreateMonster(mb, 0, 150, 100, mb.CreateString(m1_name), 0, m1_color, Any_NONE, 0, 0, 0, 0, 0, 0, stat_offset);
+    mb.Finish(monster_offset);
+    TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+    TEST_EQ_FUNC(fbb.GetSize(), 0);
+  }
+}
+
+/// This test populates data, finishes the buffer, and does move conversion after.
+void builder_move_ctor_conversion_after_finish_test() {
+  flatbuffers::FlatBufferBuilder fbb;
+  fbb.Finish(populate1(fbb));
+  flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
+  TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+  TEST_EQ_FUNC(fbb.GetSize(), 0);
+}
+
+/// This test populates data, finishes the buffer, and does move conversion after.
+void builder_move_assign_conversion_after_finish_test() {
+  flatbuffers::FlatBufferBuilder fbb;
+  flatbuffers::grpc::MessageBuilder mb;
+
+  for (int i = 0;i < 5; ++i) {
+    fbb.Finish(populate1(fbb));
+    mb = std::move(fbb);
+    TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+    TEST_EQ_FUNC(fbb.GetSize(), 0);
+  }
+}
+
+void message_builder_tests() {
+  using flatbuffers::grpc::MessageBuilder;
+  using flatbuffers::FlatBufferBuilder;
+
+  slice_allocator_tests();
+
+#ifndef __APPLE__
+  builder_move_ctor_conversion_before_finish_half_n_half_table_test();
+  builder_move_assign_conversion_before_finish_half_n_half_table_test();
+#endif // __APPLE__
+  builder_move_ctor_conversion_before_finish_test();
+  builder_move_assign_conversion_before_finish_test();
+
+  builder_move_ctor_conversion_after_finish_test();
+  builder_move_assign_conversion_after_finish_test();
+
+  BuilderTests<MessageBuilder, MessageBuilder>::all_tests();
+  BuilderTests<MessageBuilder, FlatBufferBuilder>::all_tests();
+
+  BuilderReuseTestSelector tests[6] = {
+    //REUSABLE_AFTER_RELEASE,                 // Assertion failed: (GRPC_SLICE_IS_EMPTY(slice_))
+    //REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN, // Assertion failed: (p == GRPC_SLICE_START_PTR(slice_)
+
+    REUSABLE_AFTER_RELEASE_RAW,
+    REUSABLE_AFTER_RELEASE_MESSAGE,
+    REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN,
+    REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN
+  };
+
+  BuilderReuseTests<MessageBuilder, MessageBuilder>::run_tests(TestSelector(tests, tests+6));
+  BuilderReuseTests<MessageBuilder, FlatBufferBuilder>::run_tests(TestSelector(tests, tests+6));
+}
diff --git a/grpc/tests/pom.xml b/grpc/tests/pom.xml
new file mode 100644
index 0000000..addc9fa
--- /dev/null
+++ b/grpc/tests/pom.xml
@@ -0,0 +1,73 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.google.flatbuffers</groupId>
+        <artifactId>flatbuffers-parent</artifactId>
+        <version>1.11.1</version>
+    </parent>
+    <artifactId>grpc-test</artifactId>
+    <description>Example/Test project demonstrating usage of flatbuffers with GRPC-Java instead of protobufs
+    </description>
+    <properties>
+        <gRPC.version>1.11.1</gRPC.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>com.google.flatbuffers</groupId>
+            <artifactId>flatbuffers-java</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.flatbuffers</groupId>
+            <artifactId>flatbuffers-java-grpc</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-stub</artifactId>
+            <version>${gRPC.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-netty</artifactId>
+            <version>${gRPC.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-test-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${project.basedir}</source>
+				<source>${project.basedir}/../../tests</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <!--<testSourceDirectory>${project.basedir}</testSourceDirectory>-->
+    </build>
+</project>
+