Merge "Add Grpc graph runner fuzzer" into rvc-qpr-dev
diff --git a/computepipe/tests/fuzz/Android.bp b/computepipe/tests/fuzz/Android.bp
index ee95bb1..9e4257f 100644
--- a/computepipe/tests/fuzz/Android.bp
+++ b/computepipe/tests/fuzz/Android.bp
@@ -34,6 +34,7 @@
         "-Wall",
         "-Werror",
         "-Wno-unused-parameter",
+        "-Wno-unused-variable",
     ],
     static_libs: [
         "computepipe_runner_component",
@@ -51,6 +52,7 @@
     ],
     header_libs: [
         "computepipe_runner_includes",
+        "graph_test_headers",
     ],
     include_dirs: [
         "packages/services/Car/computepipe",
@@ -101,7 +103,6 @@
     defaults: ["libcomputepipefuzz-defaults"],
     cppflags:[
         "-fexceptions",
-        "-Wno-unused-variable",
     ],
     static_libs: [
         "computepipe_prebuilt_graph",
@@ -117,3 +118,27 @@
         "LocalPrebuildGraphFuzzer.cpp",
     ],
 }
+
+cc_fuzz {
+    name: "grpc_graph_fuzzer",
+    defaults: ["libcomputepipefuzz-defaults"],
+    cppflags:[
+        "-fexceptions",
+    ],
+    static_libs: [
+        "computepipe_grpc_graph_proto",
+    ],
+    shared_libs: [
+        "computepipe_grpc_graph",
+        "libcomputepipeprotos",
+        "libgrpc++",
+        "libprotobuf-cpp-full",
+    ],
+    include_dirs: [
+        "packages/services/Car/computepipe",
+        "packages/services/Car/computepipe/runner/graph",
+    ],
+    srcs: [
+        "GrpcGraphFuzzer.cpp",
+    ],
+}
diff --git a/computepipe/tests/fuzz/Common.h b/computepipe/tests/fuzz/Common.h
index ffaf015..9934b61 100644
--- a/computepipe/tests/fuzz/Common.h
+++ b/computepipe/tests/fuzz/Common.h
@@ -33,6 +33,19 @@
             HANDLE_RESET_PHASE,           /* verify handleResetPhase */         \
             API_SUM
 
+#define GRAPH_RUNNER_BASE_ENUM                                                 \
+    GET_GRAPH_TYPE,                      /* verify GetGraphType */             \
+            GET_GRAPH_STATE,             /* verify GetGraphState */            \
+            GET_STATUS,                  /* verify GetStatus */                \
+            GET_ERROR_MESSAGE,           /* verify GetErrorMessage */          \
+            GET_SUPPORTED_GRAPH_CONFIGS, /* verify GetSupportedGraphConfigs */ \
+            SET_INPUT_STREAM_DATA,       /* verify SetInputStreamData */       \
+            SET_INPUT_STREAM_PIXEL_DATA, /* verify SetInputStreamPixelData */  \
+            START_GRAPH_PROFILING,       /* verify StartGraphProfiling */      \
+            STOP_GRAPH_PROFILING         /* verify StopGraphProfiling */
+
+const char kAddress[16] = "[::]:10000";
+
 }  // namespace test
 }  // namespace runner
 }  // namespace computepipe
diff --git a/computepipe/tests/fuzz/GrpcGraphFuzzer.cpp b/computepipe/tests/fuzz/GrpcGraphFuzzer.cpp
new file mode 100644
index 0000000..338b3f8
--- /dev/null
+++ b/computepipe/tests/fuzz/GrpcGraphFuzzer.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * 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 <android-base/logging.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gmock/gmock.h>
+#include "ClientConfig.pb.h"
+#include "Common.h"
+#include "GrpcGraph.h"
+#include "GrpcGraphServerImpl.h"
+
+using ::android::automotive::computepipe::runner::ClientConfig;
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+namespace {
+
+enum GRPC_GRAPH_FUZZ_FUNCS {
+    GRAPH_RUNNER_BASE_ENUM,
+    DISPATCH_PIXEL_DATA,            /* verify dispatchPixelData */
+    DISPATCH_SERIALIZED_DATA,       /* dispatchSerializedData */
+    DISPATCH_GRAPH_TERMINATION_MSG, /* dispatchGraphTerminationMessage */
+    RUNNER_COMP_BASE_ENUM
+};
+
+bool DoInitialization() {
+    // Initialization goes here
+    std::shared_ptr<GrpcGraphServerImpl> server;
+    server = std::make_shared<GrpcGraphServerImpl>(runner::test::kAddress);
+    std::thread t = std::thread([server]() { server->startServer(); });
+    t.detach();
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+    return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    static bool initialized = DoInitialization();
+    std::shared_ptr<PrebuiltEngineInterfaceImpl> engine;
+    std::unique_ptr<GrpcGraph> graph = std::make_unique<GrpcGraph>();
+    engine = std::make_shared<PrebuiltEngineInterfaceImpl>();
+    Status status = graph->initialize(runner::test::kAddress, engine);
+    if (status != Status::SUCCESS) {
+        LOG(ERROR) << "Initialization of GrpcGraph failed, aborting...";
+        exit(1);
+    }
+
+    // Fuzz goes here
+    FuzzedDataProvider fdp(data, size);
+    while (fdp.remaining_bytes() > runner::test::kMaxFuzzerConsumedBytes) {
+        switch (fdp.ConsumeIntegralInRange<uint32_t>(0, API_SUM - 1)) {
+            case GET_GRAPH_TYPE: {
+                graph->GetGraphType();
+                break;
+            }
+            case GET_GRAPH_STATE: {
+                graph->GetGraphState();
+                break;
+            }
+            case GET_STATUS: {
+                graph->GetStatus();
+                break;
+            }
+            case GET_ERROR_MESSAGE: {
+                graph->GetErrorMessage();
+                break;
+            }
+            case GET_SUPPORTED_GRAPH_CONFIGS: {
+                graph->GetSupportedGraphConfigs();
+                break;
+            }
+            case SET_INPUT_STREAM_DATA: {
+                graph->SetInputStreamData(/*streamIndex =*/2, /* timestamp =*/0, /* data =*/"");
+                break;
+            }
+            case SET_INPUT_STREAM_PIXEL_DATA: {
+                runner::InputFrame inputFrame(0, 0, PixelFormat::RGB, 0, nullptr);
+                graph->SetInputStreamPixelData(/*streamIndex =*/1, /*timestamp =*/0,
+                                               /*inputFrame =*/inputFrame);
+                break;
+            }
+            case START_GRAPH_PROFILING: {
+                graph->StartGraphProfiling();
+                break;
+            }
+            case STOP_GRAPH_PROFILING: {
+                graph->StopGraphProfiling();
+                break;
+            }
+            case HANDLE_CONFIG_PHASE: {
+                std::map<int, int> maxOutputPacketsPerStream;
+                ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+                e.setPhaseState(runner::PhaseState::ENTRY);
+                graph->handleConfigPhase(e);
+                break;
+            }
+            case HANDLE_EXECUTION_PHASE: {
+                std::map<int, int> maxOutputPacketsPerStream;
+                ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+                e.setPhaseState(runner::PhaseState::ENTRY);
+                graph->handleExecutionPhase(e);
+                break;
+            }
+            case HANDLE_STOP_IMMEDIATE_PHASE: {
+                std::map<int, int> maxOutputPacketsPerStream;
+                ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+                e.setPhaseState(runner::PhaseState::ENTRY);
+                graph->handleStopImmediatePhase(e);
+                break;
+            }
+            case HANDLE_STOP_WITH_FLUSH_PHASE: {
+                std::map<int, int> maxOutputPacketsPerStream;
+                ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+                e.setPhaseState(runner::PhaseState::ENTRY);
+                graph->handleStopWithFlushPhase(e);
+                break;
+            }
+            case HANDLE_RESET_PHASE: {
+                std::map<int, int> maxOutputPacketsPerStream;
+                ClientConfig e(0, 0, 0, maxOutputPacketsPerStream, proto::ProfilingType::DISABLED);
+                e.setPhaseState(runner::PhaseState::ENTRY);
+                graph->handleResetPhase(e);
+                break;
+            }
+            case DISPATCH_PIXEL_DATA: {
+                runner::InputFrame inputFrame(0, 0, PixelFormat::RGB, 0, nullptr);
+                graph->dispatchPixelData(/*streamIndex =*/1, /*timestamp =*/0,
+                                         /*inputFrame =*/inputFrame);
+                break;
+            }
+            case DISPATCH_SERIALIZED_DATA: {
+                graph->dispatchSerializedData(/*streamIndex =*/2, /* timestamp =*/0, /* data =*/"");
+                break;
+            }
+            case DISPATCH_GRAPH_TERMINATION_MSG: {
+                uint8_t status = fdp.ConsumeIntegralInRange<uint8_t>(0, Status::STATUS_MAX - 1);
+                graph->dispatchGraphTerminationMessage(static_cast<Status>(status), "");
+                break;
+            }
+            default:
+                LOG(ERROR) << "Unexpected option aborting...";
+                break;
+        }
+    }
+    return 0;
+}
+
+}  // namespace
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
diff --git a/computepipe/tests/fuzz/LocalPrebuildGraphFuzzer.cpp b/computepipe/tests/fuzz/LocalPrebuildGraphFuzzer.cpp
index cd35918..c7398e4 100644
--- a/computepipe/tests/fuzz/LocalPrebuildGraphFuzzer.cpp
+++ b/computepipe/tests/fuzz/LocalPrebuildGraphFuzzer.cpp
@@ -20,7 +20,7 @@
 #include "ClientConfig.pb.h"
 #include "Common.h"
 #include "LocalPrebuiltGraph.h"
-#include "PrebuiltEngineInterface.h"
+#include "PrebuiltEngineInterfaceImpl.h"
 
 using ::android::automotive::computepipe::runner::ClientConfig;
 
@@ -31,56 +31,7 @@
 
 namespace {
 
-enum LOCAL_PREBUILD_GRAPH_FUZZ_FUNCS {
-    GET_GRAPH_TYPE,
-    GET_GRAPH_STATE,
-    GET_STATUS,
-    GET_ERROR_MESSAGE,
-    GET_SUPPORTED_GRAPH_CONFIGS,
-    SET_INPUT_STREAM_DATA,
-    SET_INPUT_STREAM_PIXEL_DATA,
-    START_GRAPH_PROFILING,
-    STOP_GRAPH_PROFILING,
-    RUNNER_COMP_BASE_ENUM
-};
-
-// Barebones implementation of the PrebuiltEngineInterface. This implementation should suffice for
-// basic cases. More complicated use cases might need their own implementation of it.
-typedef std::function<void(int, int64_t, const runner::InputFrame&)> PixelCallback;
-typedef std::function<void(int, int64_t, std::string&&)> SerializedStreamCallback;
-typedef std::function<void(Status, std::string&&)> GraphTerminationCallback;
-class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
-private:
-    PixelCallback mPixelCallbackFn;
-    SerializedStreamCallback mSerializedStreamCallbackFn;
-    GraphTerminationCallback mGraphTerminationCallbackFn;
-
-public:
-    virtual ~PrebuiltEngineInterfaceImpl() = default;
-
-    void DispatchPixelData(int streamId, int64_t timestamp,
-                           const runner::InputFrame& frame) override {
-        mPixelCallbackFn(streamId, timestamp, frame);
-    }
-
-    void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
-        mSerializedStreamCallbackFn(streamId, timestamp, std::move(data));
-    }
-
-    void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
-        mGraphTerminationCallbackFn(status, std::move(msg));
-    }
-
-    void SetPixelCallback(PixelCallback callback) { mPixelCallbackFn = callback; }
-
-    void SetSerializedStreamCallback(SerializedStreamCallback callback) {
-        mSerializedStreamCallbackFn = callback;
-    }
-
-    void SetGraphTerminationCallback(GraphTerminationCallback callback) {
-        mGraphTerminationCallbackFn = callback;
-    }
-};
+enum LOCAL_PREBUILD_GRAPH_FUZZ_FUNCS { GRAPH_RUNNER_BASE_ENUM, RUNNER_COMP_BASE_ENUM };
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     // Initialization goes here
diff --git a/computepipe/tests/runner/graph/Android.bp b/computepipe/tests/runner/graph/Android.bp
index 14271dd..26fe1cf 100644
--- a/computepipe/tests/runner/graph/Android.bp
+++ b/computepipe/tests/runner/graph/Android.bp
@@ -12,6 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+cc_library_headers {
+    name: "graph_test_headers",
+    export_include_dirs: ["./includes"],
+}
+
 cc_test {
     name: "computepipe_prebuilt_graph_test",
     test_suites: ["device-tests"],
@@ -24,7 +29,7 @@
         "computepipe_runner_component",
         "libgtest",
         "libgmock",
-	      "libcomputepipeprotos",
+        "libcomputepipeprotos",
     ],
     shared_libs: [
         "libstubgraphimpl",
@@ -35,6 +40,7 @@
     ],
     header_libs: [
         "computepipe_runner_includes",
+        "graph_test_headers",
     ],
     include_dirs: [
         "packages/services/Car/computepipe",
@@ -63,7 +69,7 @@
     shared_libs: [
         "computepipe_grpc_graph",
         "libbase",
-	      "libcomputepipeprotos",
+        "libcomputepipeprotos",
         "libgrpc++",
         "libdl",
         "liblog",
@@ -71,6 +77,7 @@
     ],
     header_libs: [
         "computepipe_runner_includes",
+        "graph_test_headers",
     ],
     include_dirs: [
         "packages/services/Car/computepipe",
diff --git a/computepipe/tests/runner/graph/GrpcGraphTest.cpp b/computepipe/tests/runner/graph/GrpcGraphTest.cpp
index 2effb00..8a0ddc9 100644
--- a/computepipe/tests/runner/graph/GrpcGraphTest.cpp
+++ b/computepipe/tests/runner/graph/GrpcGraphTest.cpp
@@ -22,6 +22,7 @@
 #include <grpc++/grpc++.h>
 
 #include "ClientConfig.pb.h"
+#include "GrpcGraphServerImpl.h"
 #include "GrpcPrebuiltGraphService.grpc.pb.h"
 #include "GrpcPrebuiltGraphService.pb.h"
 #include "Options.pb.h"
@@ -44,190 +45,6 @@
 namespace graph {
 namespace {
 
-constexpr char kGraphName[] = "Stub graph name";
-constexpr char kSetGraphConfigMessage[] = "Stub set config message";
-constexpr char kSetDebugOptionMessage[] = "Stub set debug option message";
-constexpr char kStartGraphMessage[] = "Stub start graph message";
-constexpr char kStopGraphMessage[] = "Stub stop graph message";
-constexpr char kOutputStreamPacket[] = "Stub output stream packet";
-constexpr char kResetGraphMessage[] = "ResetGraphMessage";
-
-// This is a barebones synchronous server implementation. A better implementation would be an
-// asynchronous implementation and it is upto the graph provider to do that. This implementation
-// is very specific to tests being conducted here.
-class GrpcGraphServerImpl : public proto::GrpcGraphService::Service {
-private:
-    std::string mServerAddress;
-    std::unique_ptr<::grpc::Server> mServer;
-    std::mutex mLock;
-    std::condition_variable mShutdownCv;
-    bool mShutdown = false;
-
-public:
-    explicit GrpcGraphServerImpl(std::string address) : mServerAddress(address) {}
-
-    virtual ~GrpcGraphServerImpl() {
-        if (mServer) {
-            mServer->Shutdown();
-            std::unique_lock lock(mLock);
-            if (!mShutdown) {
-                mShutdownCv.wait_for(lock, std::chrono::seconds(10),
-                                     [this]() { return mShutdown; });
-            }
-        }
-    }
-
-    void startServer() {
-        if (mServer == nullptr) {
-            ::grpc::ServerBuilder builder;
-            builder.RegisterService(this);
-            builder.AddListeningPort(mServerAddress, ::grpc::InsecureServerCredentials());
-            mServer = builder.BuildAndStart();
-            mServer->Wait();
-            std::lock_guard lock(mLock);
-            mShutdown = true;
-            mShutdownCv.notify_one();
-        }
-    }
-
-    ::grpc::Status GetGraphOptions(::grpc::ServerContext* context,
-                                   const proto::GraphOptionsRequest* request,
-                                   proto::GraphOptionsResponse* response) override {
-        proto::Options options;
-        options.set_graph_name(kGraphName);
-        response->set_serialized_options(options.SerializeAsString());
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status SetGraphConfig(::grpc::ServerContext* context,
-                                  const proto::SetGraphConfigRequest* request,
-                                  proto::StatusResponse* response) override {
-        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
-        response->set_message(kSetGraphConfigMessage);
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status SetDebugOption(::grpc::ServerContext* context,
-                                  const proto::SetDebugRequest* request,
-                                  proto::StatusResponse* response) override {
-        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
-        response->set_message(kSetDebugOptionMessage);
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status StartGraphExecution(::grpc::ServerContext* context,
-                                       const proto::StartGraphExecutionRequest* request,
-                                       proto::StatusResponse* response) override {
-        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
-        response->set_message(kStartGraphMessage);
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status ObserveOutputStream(
-            ::grpc::ServerContext* context, const proto::ObserveOutputStreamRequest* request,
-            ::grpc::ServerWriter<proto::OutputStreamResponse>* writer) override {
-        // Write as many output packets as stream id. This is just to test different number of
-        // packets received with each stream. Also write even numbered stream as a pixel packet
-        // and odd numbered stream as a data packet.
-        for (int i = 0; i < request->stream_id(); i++) {
-            proto::OutputStreamResponse response;
-            if (request->stream_id() % 2 == 0) {
-                response.mutable_pixel_data()->set_data(kOutputStreamPacket);
-                response.mutable_pixel_data()->set_height(1);
-                response.mutable_pixel_data()->set_width(sizeof(kOutputStreamPacket));
-                response.mutable_pixel_data()->set_step(sizeof(kOutputStreamPacket));
-                response.mutable_pixel_data()->set_format(proto::PixelFormat::GRAY);
-                EXPECT_TRUE(response.has_pixel_data());
-            } else {
-                response.set_semantic_data(kOutputStreamPacket);
-                EXPECT_TRUE(response.has_semantic_data());
-            }
-            if (!writer->Write(response)) {
-                return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost");
-            }
-        }
-
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status StopGraphExecution(::grpc::ServerContext* context,
-                                      const proto::StopGraphExecutionRequest* request,
-                                      proto::StatusResponse* response) override {
-        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
-        response->set_message(kStopGraphMessage);
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status ResetGraph(::grpc::ServerContext* context,
-                              const proto::ResetGraphRequest* request,
-                              proto::StatusResponse* response) override {
-        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
-        response->set_message(kResetGraphMessage);
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status GetProfilingData(::grpc::ServerContext* context,
-                                    const proto::ProfilingDataRequest* request,
-                                    proto::ProfilingDataResponse* response) {
-        response->set_data(kSetGraphConfigMessage);
-        return ::grpc::Status::OK;
-    }
-};
-
-class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
-private:
-    std::map<int, int> mNumPacketsPerStream;
-    std::mutex mLock;
-    std::condition_variable mCv;
-    bool mGraphTerminated = false;
-
-public:
-    // Prebuilt to engine interface
-    void DispatchPixelData(int streamId, int64_t timestamp,
-                           const runner::InputFrame& frame) override {
-        ASSERT_EQ(streamId % 2, 0);
-        std::lock_guard lock(mLock);
-        if (mNumPacketsPerStream.find(streamId) == mNumPacketsPerStream.end()) {
-            mNumPacketsPerStream[streamId] = 1;
-        } else {
-            mNumPacketsPerStream[streamId]++;
-        }
-    }
-
-    void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
-        ASSERT_EQ(streamId % 2, 1);
-        std::lock_guard lock(mLock);
-        if (mNumPacketsPerStream.find(streamId) == mNumPacketsPerStream.end()) {
-            mNumPacketsPerStream[streamId] = 1;
-        } else {
-            mNumPacketsPerStream[streamId]++;
-        }
-    }
-
-    void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
-        std::lock_guard lock(mLock);
-        mGraphTerminated = true;
-        mCv.notify_one();
-    }
-
-    bool waitForTermination() {
-        std::unique_lock lock(mLock);
-        if (!mGraphTerminated) {
-            mCv.wait_for(lock, std::chrono::seconds(10), [this] { return mGraphTerminated; });
-        }
-        return mGraphTerminated;
-    }
-
-    int numPacketsForStream(int streamId) {
-        std::lock_guard lock(mLock);
-        auto it = mNumPacketsPerStream.find(streamId);
-        if (it == mNumPacketsPerStream.end()) {
-            return 0;
-        }
-        return it->second;
-    }
-};
-
 class GrpcGraphTest : public ::testing::Test {
 private:
     std::unique_ptr<GrpcGraphServerImpl> mServer;
diff --git a/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp b/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp
index d63ec51..ddc3aee 100644
--- a/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp
+++ b/computepipe/tests/runner/graph/LocalPrebuiltGraphTest.cpp
@@ -18,6 +18,7 @@
 #include "ClientConfig.pb.h"
 #include "LocalPrebuiltGraph.h"
 #include "PrebuiltEngineInterface.h"
+#include "PrebuiltEngineInterfaceImpl.h"
 #include "ProfilingType.pb.h"
 #include "RunnerComponent.h"
 #include "gmock/gmock-matchers.h"
@@ -36,44 +37,6 @@
 namespace graph {
 namespace {
 
-// Barebones implementation of the PrebuiltEngineInterface. This implementation should suffice for
-// basic cases. More complicated use cases might need their own implementation of it.
-typedef std::function<void(int, int64_t, const runner::InputFrame&)> PixelCallback;
-typedef std::function<void(int, int64_t, std::string&&)> SerializedStreamCallback;
-typedef std::function<void(Status, std::string&&)> GraphTerminationCallback;
-class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
-private:
-    PixelCallback mPixelCallbackFn;
-    SerializedStreamCallback mSerializedStreamCallbackFn;
-    GraphTerminationCallback mGraphTerminationCallbackFn;
-
-public:
-    virtual ~PrebuiltEngineInterfaceImpl() = default;
-
-    void DispatchPixelData(int streamId, int64_t timestamp,
-                           const runner::InputFrame& frame) override {
-        mPixelCallbackFn(streamId, timestamp, frame);
-    }
-
-    void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
-        mSerializedStreamCallbackFn(streamId, timestamp, std::move(data));
-    }
-
-    void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
-        mGraphTerminationCallbackFn(status, std::move(msg));
-    }
-
-    void SetPixelCallback(PixelCallback callback) { mPixelCallbackFn = callback; }
-
-    void SetSerializedStreamCallback(SerializedStreamCallback callback) {
-        mSerializedStreamCallbackFn = callback;
-    }
-
-    void SetGraphTerminationCallback(GraphTerminationCallback callback) {
-        mGraphTerminationCallbackFn = callback;
-    }
-};
-
 // The stub graph implementation is a passthrough implementation that does not run
 // any graph and returns success for all implementations. The only useful things that
 // it does for the tests are
diff --git a/computepipe/tests/runner/graph/includes/GrpcGraphServerImpl.h b/computepipe/tests/runner/graph/includes/GrpcGraphServerImpl.h
new file mode 100644
index 0000000..a168728
--- /dev/null
+++ b/computepipe/tests/runner/graph/includes/GrpcGraphServerImpl.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef CPP_COMPUTEPIPE_TESTS_RUNNER_GRAPH_INCLUDES_GRPCGRAPHSERVERIMPL_H_
+#define CPP_COMPUTEPIPE_TESTS_RUNNER_GRAPH_INCLUDES_GRPCGRAPHSERVERIMPL_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <grpc++/grpc++.h>
+
+#include "GrpcPrebuiltGraphService.grpc.pb.h"
+#include "GrpcPrebuiltGraphService.pb.h"
+#include "Options.pb.h"
+#include "PrebuiltEngineInterface.h"
+#include "PrebuiltGraph.h"
+#include "RunnerComponent.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+constexpr char kGraphName[] = "Stub graph name";
+constexpr char kSetGraphConfigMessage[] = "Stub set config message";
+constexpr char kSetDebugOptionMessage[] = "Stub set debug option message";
+constexpr char kStartGraphMessage[] = "Stub start graph message";
+constexpr char kStopGraphMessage[] = "Stub stop graph message";
+constexpr char kOutputStreamPacket[] = "Stub output stream packet";
+constexpr char kResetGraphMessage[] = "ResetGraphMessage";
+
+// This is a barebones synchronous server implementation. A better implementation would be an
+// asynchronous implementation and it is upto the graph provider to do that. This implementation
+// is very specific to tests being conducted here.
+class GrpcGraphServerImpl : public proto::GrpcGraphService::Service {
+private:
+    std::string mServerAddress;
+    std::unique_ptr<::grpc::Server> mServer;
+    std::mutex mLock;
+    std::condition_variable mShutdownCv;
+    bool mShutdown = false;
+
+public:
+    explicit GrpcGraphServerImpl(std::string address) : mServerAddress(address) {}
+
+    virtual ~GrpcGraphServerImpl() {
+        if (mServer) {
+            mServer->Shutdown();
+            std::unique_lock lock(mLock);
+            if (!mShutdown) {
+                mShutdownCv.wait_for(lock, std::chrono::seconds(10),
+                                     [this]() { return mShutdown; });
+            }
+        }
+    }
+
+    void startServer() {
+        if (mServer == nullptr) {
+            ::grpc::ServerBuilder builder;
+            builder.RegisterService(this);
+            builder.AddListeningPort(mServerAddress, ::grpc::InsecureServerCredentials());
+            mServer = builder.BuildAndStart();
+            mServer->Wait();
+            std::lock_guard lock(mLock);
+            mShutdown = true;
+            mShutdownCv.notify_one();
+        }
+    }
+
+    ::grpc::Status GetGraphOptions(::grpc::ServerContext* context,
+                                   const proto::GraphOptionsRequest* request,
+                                   proto::GraphOptionsResponse* response) override {
+        proto::Options options;
+        options.set_graph_name(kGraphName);
+        response->set_serialized_options(options.SerializeAsString());
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status SetGraphConfig(::grpc::ServerContext* context,
+                                  const proto::SetGraphConfigRequest* request,
+                                  proto::StatusResponse* response) override {
+        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+        response->set_message(kSetGraphConfigMessage);
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status SetDebugOption(::grpc::ServerContext* context,
+                                  const proto::SetDebugRequest* request,
+                                  proto::StatusResponse* response) override {
+        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+        response->set_message(kSetDebugOptionMessage);
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status StartGraphExecution(::grpc::ServerContext* context,
+                                       const proto::StartGraphExecutionRequest* request,
+                                       proto::StatusResponse* response) override {
+        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+        response->set_message(kStartGraphMessage);
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status ObserveOutputStream(
+            ::grpc::ServerContext* context, const proto::ObserveOutputStreamRequest* request,
+            ::grpc::ServerWriter<proto::OutputStreamResponse>* writer) override {
+        // Write as many output packets as stream id. This is just to test different number of
+        // packets received with each stream. Also write even numbered stream as a pixel packet
+        // and odd numbered stream as a data packet.
+        for (int i = 0; i < request->stream_id(); i++) {
+            proto::OutputStreamResponse response;
+            if (request->stream_id() % 2 == 0) {
+                response.mutable_pixel_data()->set_data(kOutputStreamPacket);
+                response.mutable_pixel_data()->set_height(1);
+                response.mutable_pixel_data()->set_width(sizeof(kOutputStreamPacket));
+                response.mutable_pixel_data()->set_step(sizeof(kOutputStreamPacket));
+                response.mutable_pixel_data()->set_format(proto::PixelFormat::GRAY);
+                EXPECT_TRUE(response.has_pixel_data());
+            } else {
+                response.set_semantic_data(kOutputStreamPacket);
+                EXPECT_TRUE(response.has_semantic_data());
+            }
+            if (!writer->Write(response)) {
+                return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost");
+            }
+        }
+
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status StopGraphExecution(::grpc::ServerContext* context,
+                                      const proto::StopGraphExecutionRequest* request,
+                                      proto::StatusResponse* response) override {
+        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+        response->set_message(kStopGraphMessage);
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status ResetGraph(::grpc::ServerContext* context,
+                              const proto::ResetGraphRequest* request,
+                              proto::StatusResponse* response) override {
+        response->set_code(proto::RemoteGraphStatusCode::SUCCESS);
+        response->set_message(kResetGraphMessage);
+        return ::grpc::Status::OK;
+    }
+
+    ::grpc::Status GetProfilingData(::grpc::ServerContext* context,
+                                    const proto::ProfilingDataRequest* request,
+                                    proto::ProfilingDataResponse* response) {
+        response->set_data(kSetGraphConfigMessage);
+        return ::grpc::Status::OK;
+    }
+};
+
+class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
+private:
+    std::map<int, int> mNumPacketsPerStream;
+    std::mutex mLock;
+    std::condition_variable mCv;
+    bool mGraphTerminated = false;
+
+public:
+    // Prebuilt to engine interface
+    void DispatchPixelData(int streamId, int64_t timestamp,
+                           const runner::InputFrame& frame) override {
+        ASSERT_EQ(streamId % 2, 0);
+        std::lock_guard lock(mLock);
+        if (mNumPacketsPerStream.find(streamId) == mNumPacketsPerStream.end()) {
+            mNumPacketsPerStream[streamId] = 1;
+        } else {
+            mNumPacketsPerStream[streamId]++;
+        }
+    }
+
+    void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
+        ASSERT_EQ(streamId % 2, 1);
+        std::lock_guard lock(mLock);
+        if (mNumPacketsPerStream.find(streamId) == mNumPacketsPerStream.end()) {
+            mNumPacketsPerStream[streamId] = 1;
+        } else {
+            mNumPacketsPerStream[streamId]++;
+        }
+    }
+
+    void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
+        std::lock_guard lock(mLock);
+        mGraphTerminated = true;
+        mCv.notify_one();
+    }
+
+    bool waitForTermination() {
+        std::unique_lock lock(mLock);
+        if (!mGraphTerminated) {
+            mCv.wait_for(lock, std::chrono::seconds(10), [this] { return mGraphTerminated; });
+        }
+        return mGraphTerminated;
+    }
+
+    int numPacketsForStream(int streamId) {
+        std::lock_guard lock(mLock);
+        auto it = mNumPacketsPerStream.find(streamId);
+        if (it == mNumPacketsPerStream.end()) {
+            return 0;
+        }
+        return it->second;
+    }
+};
+
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CPP_COMPUTEPIPE_TESTS_RUNNER_GRAPH_INCLUDES_GRPCGRAPHSERVERIMPL_H_
diff --git a/computepipe/tests/runner/graph/includes/PrebuiltEngineInterfaceImpl.h b/computepipe/tests/runner/graph/includes/PrebuiltEngineInterfaceImpl.h
new file mode 100644
index 0000000..70326ab
--- /dev/null
+++ b/computepipe/tests/runner/graph/includes/PrebuiltEngineInterfaceImpl.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef CPP_COMPUTEPIPE_TESTS_RUNNER_GRAPH_INCLUDES_PREBUILTENGINEINTERFACEIMPL_H_
+#define CPP_COMPUTEPIPE_TESTS_RUNNER_GRAPH_INCLUDES_PREBUILTENGINEINTERFACEIMPL_H_
+
+#include <string>
+
+#include "ClientConfig.pb.h"
+#include "LocalPrebuiltGraph.h"
+#include "PrebuiltEngineInterface.h"
+#include "ProfilingType.pb.h"
+#include "RunnerComponent.h"
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "types/Status.h"
+
+namespace android {
+namespace automotive {
+namespace computepipe {
+namespace graph {
+
+// Barebones implementation of the PrebuiltEngineInterface. This implementation should suffice for
+// basic cases. More complicated use cases might need their own implementation of it.
+typedef std::function<void(int, int64_t, const runner::InputFrame&)> PixelCallback;
+typedef std::function<void(int, int64_t, std::string&&)> SerializedStreamCallback;
+typedef std::function<void(Status, std::string&&)> GraphTerminationCallback;
+class PrebuiltEngineInterfaceImpl : public PrebuiltEngineInterface {
+private:
+    PixelCallback mPixelCallbackFn;
+    SerializedStreamCallback mSerializedStreamCallbackFn;
+    GraphTerminationCallback mGraphTerminationCallbackFn;
+
+public:
+    virtual ~PrebuiltEngineInterfaceImpl() = default;
+
+    void DispatchPixelData(int streamId, int64_t timestamp,
+                           const runner::InputFrame& frame) override {
+        mPixelCallbackFn(streamId, timestamp, frame);
+    }
+
+    void DispatchSerializedData(int streamId, int64_t timestamp, std::string&& data) override {
+        mSerializedStreamCallbackFn(streamId, timestamp, std::move(data));
+    }
+
+    void DispatchGraphTerminationMessage(Status status, std::string&& msg) override {
+        mGraphTerminationCallbackFn(status, std::move(msg));
+    }
+
+    void SetPixelCallback(PixelCallback callback) { mPixelCallbackFn = callback; }
+
+    void SetSerializedStreamCallback(SerializedStreamCallback callback) {
+        mSerializedStreamCallbackFn = callback;
+    }
+
+    void SetGraphTerminationCallback(GraphTerminationCallback callback) {
+        mGraphTerminationCallbackFn = callback;
+    }
+};
+
+}  // namespace graph
+}  // namespace computepipe
+}  // namespace automotive
+}  // namespace android
+
+#endif  // CPP_COMPUTEPIPE_TESTS_RUNNER_GRAPH_INCLUDES_PREBUILTENGINEINTERFACEIMPL_H_