robert-min / handson-go

Go-lang hands on guide
0 stars 0 forks source link

Chapter8. gRPC - multi service #24

Open robert-min opened 1 year ago

robert-min commented 1 year ago

Muilti service

robert-min commented 1 year ago

Multi service 제공을 위한 프로토콜 버퍼 명세 작성

syntax = "proto3";

import "users.proto";

option go_package = "github.com/handson-go/chap8/multiple-services/service";

service Repo {
    rpc GetRepos (RepoGetRequest) returns (RepoGetReply) {}
}

message RepoGetRequest {
    string id = 1;
    string create_id = 2;
}

message Repository {
    string id = 1;
    string name = 2;
    string url = 3;
    User owner = 4;
}

message RepoGetReply {
    repeated Repository repo = 1;
}
protoc --go_out=. --go_opt=paths=source_relative \  
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
users.proto repositories.proto
robert-min commented 1 year ago

Multi Service server 코드

package main

import (
    "context"
    "errors"
    "log"
    "net"
    "os"
    "strings"

    svc "github.com/handson-go/chap8/multiple-services/service"
    "google.golang.org/grpc"
)

type userSerivce struct {
    svc.UnimplementedUsersServer
}

type repoService struct {
    svc.UnimplementedRepoServer
}

func (s *userSerivce) GetUser(ctx context.Context, in *svc.UserGetRequest) (*svc.UserGetReply, error) {
    log.Printf("Received request for user with Email: %s Id: %s\n", in.Email, in.Id)
    componets := strings.Split(in.Email, "@")
    if len(componets) != 2 {
        return nil, errors.New("invalid email address")
    }
    u := svc.User{
        Id:        in.Id,
        FirstName: componets[0],
        LastName:  componets[1],
        Age:       36,
    }
    return &svc.UserGetReply{User: &u}, nil
}

func (s *repoService) GetRepos(ctx context.Context, in *svc.RepoGetRequest) (*svc.RepoGetReply, error) {
    log.Printf(
        "Received request for repo with CreateId: %s Id: %s\n",
        in.CreateId,
        in.Id,
    )
    repo := svc.Repository{
        Id:    in.Id,
        Name:  "test repo",
        Url:   "https://git.example.com/test/repo",
        Owner: &svc.User{Id: in.CreateId, FirstName: "kim"},
    }
    r := svc.RepoGetReply{
        Repo: []*svc.Repository{&repo},
    }
    return &r, nil
}

func registerServices(s *grpc.Server) {
    svc.RegisterUsersServer(s, &userSerivce{})
    svc.RegisterRepoServer(s, &repoService{})
}

func startServer(s *grpc.Server, l net.Listener) error {
    return s.Serve(l)
}

func main() {
    listenAddr := os.Getenv("LISTEN_ADDR")
    if len(listenAddr) == 0 {
        listenAddr = ":50051"
    }

    lis, err := net.Listen("tcp", listenAddr)
    if err != nil {
        log.Fatal(err)
    }
    s := grpc.NewServer()
    registerServices(s)
    log.Fatal(startServer(s, lis))
}
robert-min commented 1 year ago

Multi Service test code

package main

import (
    "context"
    "log"
    "net"
    "testing"

    svc "github.com/handson-go/chap8/multiple-services/service"
    "google.golang.org/grpc"
    "google.golang.org/grpc/test/bufconn"
)

func startTestGRPCServer() (*grpc.Server, *bufconn.Listener) {
    l := bufconn.Listen(10)
    s := grpc.NewServer()
    registerServices(s)

    go func() {
        err := startServer(s, l)
        if err != nil {
            log.Fatal(err)
        }
    }()
    return s, l
}

func TestUserService(t *testing.T) {
    s, l := startTestGRPCServer()
    defer s.GracefulStop()

    bufconnDialer := func(ctx context.Context, addr string) (net.Conn, error) {
        return l.Dial()
    }

    client, err := grpc.DialContext(
        context.Background(),
        "",
        grpc.WithInsecure(),
        grpc.WithContextDialer(bufconnDialer),
    )
    if err != nil {
        t.Fatal(err)
    }

    usersClient := svc.NewUsersClient(client)
    resp, err := usersClient.GetUser(
        context.Background(),
        &svc.UserGetRequest{
            Id:    "foo-bar",
            Email: "kim@do.com",
        },
    )
    if err != nil {
        t.Fatal(err)
    }

    if resp.User.FirstName != "kim" {
        t.Errorf(
            "Expected FirstName to be: kim, Got: %s",
            resp.User.FirstName,
        )
    }
}

func TestRepoService(t *testing.T) {
    s, l := startTestGRPCServer()
    defer s.GracefulStop()

    bufconnDialer := func(ctx context.Context, addr string) (net.Conn, error) {
        return l.Dial()
    }

    client, err := grpc.DialContext(
        context.Background(),
        "",
        grpc.WithInsecure(),
        grpc.WithContextDialer(bufconnDialer),
    )
    if err != nil {
        t.Fatal(err)
    }

    repoClient := svc.NewRepoClient(client)
    resp, err := repoClient.GetRepos(
        context.Background(),
        &svc.RepoGetRequest{
            CreateId: "user-11",
            Id:       "repo-11",
        },
    )
    if err != nil {
        t.Fatal(err)
    }

    if len(resp.Repo) != 1 {
        t.Fatalf("Expected to get back 1 repo, got back: %d repos", len(resp.Repo))
    }
    gotId := resp.Repo[0].Id
    gotOwnerId := resp.Repo[0].Owner.Id

    if gotId != "repo-11" {
        t.Errorf(
            "Expected Repo ID to be: repo-11, Got: %s",
            gotId,
        )
    }

    if gotOwnerId != "user-11" {
        t.Errorf(
            "Expected Repo ID to be: user-11, Got: %s",
            gotOwnerId,
        )
    }
}