Skip to content

Commit

Permalink
feat: Add C++ grpc example
Browse files Browse the repository at this point in the history
  • Loading branch information
satreix committed Jul 12, 2024
1 parent 57e4ec1 commit ec49470
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
build --cxxopt='-std=c++17'

# On macOS with an installed oppenssl, this prevent Bazel from looking in /usr/local/include and failing the boringssl compile.
# This does on the other hand brak the python interpreter in rules_python
# build --sandbox_block_path=/usr/local

# Ensure rules_haskell picks up the correct toolchain on Mac.
build --action_env=BAZEL_USE_CPP_ONLY_TOOLCHAIN=1

Expand Down
5 changes: 4 additions & 1 deletion src/cpp/hello_world/greet/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ cc_library(
name = "greet",
srcs = ["greet.cc"],
hdrs = ["greet.h"],
visibility = ["//src/cpp/hello_world:__pkg__"],
visibility = [
"//src/cpp/hello_world:__pkg__",
"//src/cpp/hello_world/server:__pkg__",
],
deps = ["@fmt"],
)

Expand Down
33 changes: 33 additions & 0 deletions src/cpp/hello_world/server/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@io_bazel_rules_go//go:def.bzl", "go_test")
load("@rules_cc//cc:defs.bzl", "cc_binary")

cc_binary(
name = "server",
srcs = ["server.cc"],
deps = [
"//src/cpp/hello_world/greet",
"//src/proto/helloworld:helloworld_cc_grpc",
"@gflags",
"@grpc//:grpc++",
"@grpc//:grpc++_reflection",
],
)

build_test(
name = "server_build_test",
targets = [":server"],
)

go_test(
name = "server_test",
size = "medium",
timeout = "short",
srcs = ["server_test.go"],
data = [":server"],
deps = [
"//src/proto/helloworld",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
"@org_golang_google_grpc//:go_default_library",
],
)
45 changes: 45 additions & 0 deletions src/cpp/hello_world/server/server.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include <iostream>

#include "gflags/gflags.h"
#include <grpcpp/ext/proto_server_reflection_plugin.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/health_check_service_interface.h>

#include "src/proto/helloworld/helloworld.grpc.pb.h"
#include "src/cpp/hello_world/greet/greet.h"

using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using helloworld::HelloReply;
using helloworld::HelloRequest;
using helloworld::Greeter;

DEFINE_string(address, "0.0.0.0:50051", "address to bind to");

class GreeterServiceImpl final : public Greeter::Service {
Status SayHello(ServerContext *context,
const HelloRequest *request,
HelloReply *reply) override {
reply->set_message(greet::greet(request->name()));
return Status::OK;
}
};

int
main(int argc, char **argv) {
gflags::ParseCommandLineFlags(&argc, &argv, true);

GreeterServiceImpl service;

grpc::EnableDefaultHealthCheckService(true);
grpc::reflection::InitProtoReflectionServerBuilderPlugin();
ServerBuilder builder;
builder.AddListeningPort(FLAGS_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cerr << "Server listening on " << FLAGS_address << std::endl;
server->Wait();
return 0;
}
111 changes: 111 additions & 0 deletions src/cpp/hello_world/server/server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package main_test

import (
"context"
"fmt"
"log"
"net"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"time"

"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/satreix/everest/src/proto/helloworld"
"google.golang.org/grpc"
)

func TestEnd2End(t *testing.T) {
const iface = "127.0.0.1"
port, err := freeTCPPort("tcp", iface)
if err != nil {
t.Fatalf("could not get a free port: %s", err)
}
addr := fmt.Sprintf("%s:%d", iface, port)
t.Logf("addr: %s", addr)

serverBin, err := findBinary("//src/cpp/hello_world/server", "server")
if err != nil {
t.Fatalf("error finding server: %s", err)
}
t.Log("server: " + serverBin)

serverCmd := exec.Command(serverBin, fmt.Sprintf("--address=%s", addr))
if err := serverCmd.Start(); err != nil {
t.Fatalf("error starting server: %s", err)
}
defer serverCmd.Process.Kill()
t.Logf("serverCmd: %s", strings.Join(serverCmd.Args, " "))

// FIXME make this not time based but instead retry the assertion
time.Sleep(2 * time.Second)

conn, err := grpc.Dial(addr, grpc.WithInsecure())
if err != nil {
t.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()

client := helloworld.NewGreeterClient(conn)

resp, err := client.SayHello(context.Background(), &helloworld.HelloRequest{
Name: "Alice",
})
if err != nil {
t.Fatalf("SayHello failed: %v", err)
}

expectedMessage := "Hello, Alice!"
if resp.Message != expectedMessage {
t.Fatalf("Unexpected response: got %q, want %q", resp.Message, expectedMessage)
}
}

func findBinary(pkg, name string) (string, error) {
// workaround for external targets
if strings.HasPrefix(pkg, "@") {
pkg = "external/" + strings.TrimPrefix(pkg, "@")
}
pkg = strings.TrimPrefix(pkg, "//")

rfs, err := bazel.ListRunfiles()
if err != nil {
return "", err
}
for idx, rf := range rfs {
if rf.ShortPath == filepath.Join(pkg, name) {
return rf.Path, nil
}

log.Printf("%d. %#v", idx, rf)
}

bin, found := bazel.FindBinary(pkg, name)
if !found {
return "", fmt.Errorf("couldn't find binary for %s:%s", pkg, name)
}

fi, err := os.Stat(bin)
if err != nil {
panic(err.Error())
}

if fi.Mode().IsDir() {
return bin + "/" + runtime.GOOS + "_" + runtime.GOARCH + "_stripped/" + name, nil
}

return bin, nil
}

func freeTCPPort(network, iface string) (int, error) {
l, err := net.Listen(network, iface+":0")
if err != nil {
return 0, err
}
defer l.Close()

return l.Addr().(*net.TCPAddr).Port, nil
}
15 changes: 15 additions & 0 deletions src/proto/helloworld/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
load("@grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library")
load("@grpc-java//:java_grpc_library.bzl", "java_grpc_library")
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
load("@rules_java//java:defs.bzl", "java_proto_library")
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@rules_rust//proto/protobuf:defs.bzl", "rust_grpc_library")
Expand All @@ -14,6 +16,19 @@ proto_library(
visibility = ["//visibility:public"],
)

cc_proto_library(
name = "helloworld_cc_proto",
deps = [":helloworld_proto"],
)

cc_grpc_library(
name = "helloworld_cc_grpc",
srcs = [":helloworld_proto"],
grpc_only = True,
visibility = ["//src/cpp/hello_world/server:__pkg__"],
deps = [":helloworld_cc_proto"],
)

go_proto_library(
name = "helloworld_go_proto",
compilers = ["@io_bazel_rules_go//proto:go_grpc"],
Expand Down

0 comments on commit ec49470

Please sign in to comment.