<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Toran Sahu on Medium]]></title>
        <description><![CDATA[Stories by Toran Sahu on Medium]]></description>
        <link>https://medium.com/@toransahu?source=rss-b49056382ee6------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*SqkvQSP_MjQCG2XV.</url>
            <title>Stories by Toran Sahu on Medium</title>
            <link>https://medium.com/@toransahu?source=rss-b49056382ee6------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 03 Apr 2026 21:07:53 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@toransahu/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Part-3: Building a basic microservice with bidirectional-streaming gRPC using Golang]]></title>
            <link>https://toransahu.medium.com/part-3-building-a-basic-microservice-with-bidirectional-streaming-grpc-using-golang-c5681a61da8a?source=rss-b49056382ee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/c5681a61da8a</guid>
            <category><![CDATA[bidirectional]]></category>
            <category><![CDATA[protobuf]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[grpc]]></category>
            <category><![CDATA[streaming]]></category>
            <dc:creator><![CDATA[Toran Sahu]]></dc:creator>
            <pubDate>Thu, 25 Feb 2021 13:22:41 GMT</pubDate>
            <atom:updated>2021-02-25T13:22:41.105Z</atom:updated>
            <content:encoded><![CDATA[<p>If you have been through <a href="https://toransahu.medium.com/part-2-building-a-basic-microservice-with-unidirectional-streaming-grpc-using-golang-337b580bedbe">part-2</a> of this blog series, you would have already got to know that the gRPC framework has got support for uni-directional streaming RPCs. But that is not the end. gRPC has support for bi-directional RPCs as well. Being said that, a gRPC client and a gRPC server can stream requests and responses simultaneously utilizing the same TCP connection.</p><h3>Objective</h3><p>In this blog, you’ll get to know what is bi-directional streaming RPCs. How to implement, test, and run them using a live, fully functional example.</p><blockquote><em>Previously in the </em><a href="https://toransahu.medium.com/part-2-building-a-basic-microservice-with-unidirectional-streaming-grpc-using-golang-337b580bedbe"><em>part-2</em></a><em> of this blog series, we’ve learned the basics of uni-directional streaming gRPCs, how to implement those gRPC, how to write unit tests, how to launch the server &amp; client. </em><a href="https://toransahu.medium.com/part-2-building-a-basic-microservice-with-unidirectional-streaming-grpc-using-golang-337b580bedbe"><em>part-2</em></a><em> walks you through a step-by-step guide to implement a </em>Stack Machine<em> server &amp; client leveraging the uni-directional streaming RPC.</em></blockquote><blockquote><em>If you’ve missed that, it is highly recommended to go through it to get familiar with the basics of the gRPC framework &amp; streaming RPCs.</em></blockquote><h3>Introduction</h3><p>Let’s understand how bi-directional streaming RPCs works at a very high-level.</p><p>Bidirectional streaming RPCs where:</p><ul><li>both sides send a sequence of messages using a read-write stream</li><li>the two streams operate independently, so clients and servers can read and write in whatever order they like</li><li>for example, the server could wait to receive all the client messages before writing its responses, or it could alternately read a message then write a message, or some other combination of reads and writes</li></ul><p>The best thing is, the order of messages in each stream is preserved.</p><p>Now let’s improve the <em>“Stack Machine”</em> server &amp; client codes to support bidirectional streaming.</p><h3>Implementing Bidirectional Streaming RPC</h3><p>We already have Server-streaming RPC ServerStreamingExecute() to handle FIB operation which streams the numbers from Fibonacci series, and Client-streaming RPC Execute() to handle the stream of instructions to perform basic ADD/SUB/MUL/DIV operations and return a single response.</p><p>In this blog we’ll merge both the functionality to make the Execute() RPC a bidirectional streaming one.</p><h3>Update the protobuf</h3><p>Let’s update the machine/machine.proto to make Execute() a bi-directional (server &amp; client streaming) RPC, so that the client can stream the instructions rather than sending a set of instructions to the server &amp; the server can respond with a stream of results. Doing so, we&#39;re getting rid of InstructionSet and ServerStreamingExecute().</p><p>The updated machine/machine.proto now looks like:</p><pre>service Machine {<br>-     rpc Execute(stream Instruction) returns (Result) {}<br>-     rpc ServerStreamingExecute(InstructionSet) returns (stream Result) {}<br>+     rpc Execute(stream Instruction) returns (stream Result) {}<br> }</pre><pre>                source: <a href="https://github.com/toransahu/grpc-eg-go/commit/e0042dc83d2d34ad15af284a2d5c3318f2f18eeb">machine/machine.proto</a></pre><p>Notice the stream keyword at two places in the Execute() RPC declaration.</p><h3>Generating the updated client and server interface Go code</h3><p>Now lets generate an updated golang code from the machine/machine.proto by running:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ SRC_DIR=./<br>$ DST_DIR=$SRC_DIR<br>$ protoc \<br>  -I=$SRC_DIR \<br>  --go_out=plugins=grpc:$DST_DIR \<br>  $SRC_DIR/machine/machine.proto</pre><p>You’ll notice that declaration of ServerStreamingExecute() has been removed from MachineServer &amp; MachineClient interfaces. However the signature of Execute() is intact.</p><pre>...</pre><pre> type MachineServer interface {<br>    Execute(Machine_ExecuteServer) error<br>-   ServerStreamingExecute(*InstructionSet, Machine_ServerStreamingExecuteServer) error<br> }</pre><pre>...</pre><pre> type MachineClient interface {<br>    Execute(ctx context.Context, opts ...grpc.CallOption) (Machine_ExecuteClient, error)<br>-   ServerStreamingExecute(ctx context.Context, in *InstructionSet, opts ...grpc.CallOption) (Machine_ServerStreamingExecuteClient, error)<br> }</pre><pre>...</pre><pre>                source: <a href="https://github.com/toransahu/grpc-eg-go/commit/f03265623e0b1b037e831a34d09e104f62955a89">machine/machine.pb.go</a></pre><h3>Update the Server</h3><p>Now we need to update the server code to make Execute() a bi-directional (server &amp; client streaming) RPC so that it should be able to accept stream the instructions from the client and at the same time it can respond with a stream of results.</p><pre>func (s *MachineServer) Execute(stream machine.Machine_ExecuteServer) error {<br>    var stack stack.Stack<br>    for {<br>        instruction, err := stream.Recv()<br>        if err == io.EOF {<br>            log.Println(&quot;EOF&quot;)<br>            return nil<br>        }<br>        if err != nil {<br>            return err<br>        }</pre><pre>        operand := instruction.GetOperand()<br>        operator := instruction.GetOperator()<br>        op_type := OperatorType(operator)</pre><pre>        fmt.Printf(&quot;Operand: %v, Operator: %v\n&quot;, operand, operator)</pre><pre>        switch op_type {<br>        case PUSH:<br>            stack.Push(float32(operand))<br>        case POP:<br>            stack.Pop()<br>        case ADD, SUB, MUL, DIV:<br>            item2, popped := stack.Pop()<br>            item1, popped := stack.Pop()</pre><pre>            if !popped {<br>                return status.Error(codes.Aborted, &quot;Invalid sets of instructions. Execution aborted&quot;)<br>            }</pre><pre>            var res float32<br>            if op_type == ADD {<br>                res = item1 + item2<br>            } else if op_type == SUB {<br>                res = item1 - item2<br>            } else if op_type == MUL {<br>                res = item1 * item2<br>            } else if op_type == DIV {<br>                res = item1 / item2<br>            }</pre><pre>            stack.Push(res)<br>            if err := stream.Send(&amp;machine.Result{Output: float32(res)}); err != nil {<br>                return err<br>            }<br>        case FIB:<br>            n, popped := stack.Pop()</pre><pre>            if !popped {<br>                return status.Error(codes.Aborted, &quot;Invalid sets of instructions. Execution aborted&quot;)<br>            }</pre><pre>            if op_type == FIB {<br>                for f := range utils.FibonacciRange(int(n)) {<br>                    if err := stream.Send(&amp;machine.Result{Output: float32(f)}); err != nil {<br>                        return err<br>                    }<br>                }<br>            }<br>        default:<br>            return status.Errorf(codes.Unimplemented, &quot;Operation &#39;%s&#39; not implemented yet&quot;, operator)<br>        }<br>    }<br>}</pre><pre>                   source: <a href="https://github.com/toransahu/grpc-eg-go/commit/a4e39d671a604d135822868ed7169402c19d0c1d">server/machine.go</a></pre><h3>Update the Client</h3><p>Let’s update the client code to make client.Execute() a bi-directional streaming RPC so that the client can stream the instructions to the server and can receive a stream of results at the same time.</p><pre>func runExecute(client machine.MachineClient, instructions []*machine.Instruction) {<br>    log.Printf(&quot;Streaming %v&quot;, instructions)<br>    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)<br>    defer cancel()<br>    stream, err := client.Execute(ctx)<br>    if err != nil {<br>        log.Fatalf(&quot;%v.Execute(ctx) = %v, %v: &quot;, client, stream, err)<br>    }<br>    waitc := make(chan struct{})<br>    go func() {<br>        for {<br>            result, err := stream.Recv()<br>            if err == io.EOF {<br>                log.Println(&quot;EOF&quot;)<br>                close(waitc)<br>                return<br>            }<br>            if err != nil {<br>                log.Printf(&quot;Err: %v&quot;, err)<br>            }<br>            log.Printf(&quot;output: %v&quot;, result.GetOutput())<br>        }<br>    }()</pre><pre>    for _, instruction := range instructions {<br>        if err := stream.Send(instruction); err != nil {<br>            log.Fatalf(&quot;%v.Send(%v) = %v: &quot;, stream, instruction, err)<br>        }<br>        time.Sleep(500 * time.Millisecond)<br>    }<br>    if err := stream.CloseSend(); err != nil {<br>        log.Fatalf(&quot;%v.CloseSend() got error %v, want %v&quot;, stream, err, nil)<br>    }<br>    &lt;-waitc<br>}</pre><pre>                  source: <a href="https://github.com/toransahu/grpc-eg-go/commit/fe079ba56b348c5ce2e465501be5ee6093bdf5c3">client/machine.go</a></pre><h3>Test</h3><p>Before we start updating the unit test, let’s generate mocks for MachineClient, Machine_ExecuteClient, and Machine_ExecuteServer interfaces to mock the stream type while testing the bidirectional streaming RPC Execute().</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ mockgen github.com/toransahu/grpc-eg-go/machine MachineClient,Machine_ExecuteServer,Machine_ExecuteClient &gt; mock_machine/machine_mock.go</pre><p>The updated mock_machine/machine_mock.go should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/85a45cec309e3cabb58ca9e46f64fe669b899cf1">this</a>.</p><p>Now, we’re good to write a unit test for bidirectional streaming RPC Execute().</p><h4>Server</h4><p>Let’s update the unit test to test the server-side logic of Execute() RPC for bidirectional streaming using mock:</p><pre>func TestExecute(t *testing.T) {<br>    s := MachineServer{}</pre><pre>    ctrl := gomock.NewController(t)<br>    defer ctrl.Finish()<br>    mockServerStream := mock_machine.NewMockMachine_ExecuteServer(ctrl)</pre><pre>    mockResults := []*machine.Result{}<br>    callRecv1 := mockServerStream.EXPECT().Recv().Return(&amp;machine.Instruction{Operand: 1, Operator: &quot;PUSH&quot;}, nil)<br>    callRecv2 := mockServerStream.EXPECT().Recv().Return(&amp;machine.Instruction{Operand: 2, Operator: &quot;PUSH&quot;}, nil).After(callRecv1)<br>    callRecv3 := mockServerStream.EXPECT().Recv().Return(&amp;machine.Instruction{Operator: &quot;MUL&quot;}, nil).After(callRecv2)<br>    callRecv4 := mockServerStream.EXPECT().Recv().Return(&amp;machine.Instruction{Operand: 3, Operator: &quot;PUSH&quot;}, nil).After(callRecv3)<br>    callRecv5 := mockServerStream.EXPECT().Recv().Return(&amp;machine.Instruction{Operator: &quot;ADD&quot;}, nil).After(callRecv4)<br>    callRecv6 := mockServerStream.EXPECT().Recv().Return(&amp;machine.Instruction{Operator: &quot;FIB&quot;}, nil).After(callRecv5)<br>    mockServerStream.EXPECT().Recv().Return(nil, io.EOF).After(callRecv6)<br>    mockServerStream.EXPECT().Send(gomock.Any()).DoAndReturn(<br>        func(result *machine.Result) error {<br>            mockResults = append(mockResults, result)<br>            return nil<br>        }).AnyTimes()<br>    wants := []float32{2, 5, 0, 1, 1, 2, 3, 5}</pre><pre>    err := s.Execute(mockServerStream)<br>    if err != nil {<br>        t.Errorf(&quot;Execute(%v) got unexpected error: %v&quot;, mockServerStream, err)<br>    }<br>    for i, result := range mockResults {<br>        got := result.GetOutput()<br>        want := wants[i]<br>        if got != want {<br>            t.Errorf(&quot;got %v, want %v&quot;, got, want)<br>        }<br>    }<br>}</pre><pre>               source: <a href="https://github.com/toransahu/grpc-eg-go/commit/01bd6dfcebd100f1c027ed13e8e7d52871bc8aff">server/machine_test.go</a></pre><p>Let’s run the unit test:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go test server/machine.go server/machine_test.go<br>ok      command-line-arguments  0.004s</pre><h4>Client</h4><p>Now, add unit test to test client-side logic of Execute() RPC for bidirectional streaming using mock:</p><pre>func testExecute(t *testing.T, client machine.MachineClient) {<br>    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)<br>    defer cancel()</pre><pre>    instructions := []*machine.Instruction{}<br>    instructions = append(instructions, &amp;machine.Instruction{Operand: 5, Operator: &quot;PUSH&quot;})<br>    instructions = append(instructions, &amp;machine.Instruction{Operand: 6, Operator: &quot;PUSH&quot;})<br>    instructions = append(instructions, &amp;machine.Instruction{Operator: &quot;MUL&quot;})</pre><pre>    stream, err := client.Execute(ctx)<br>    if err != nil {<br>        log.Fatalf(&quot;%v.Execute(%v) = _, %v: &quot;, client, ctx, err)<br>    }<br>    for _, instruction := range instructions {<br>        if err := stream.Send(instruction); err != nil {<br>            log.Fatalf(&quot;%v.Send(%v) = %v: &quot;, stream, instruction, err)<br>        }<br>    }<br>    result, err := stream.Recv()<br>    if err != nil {<br>        log.Fatalf(&quot;%v.Recv() got error %v, want %v&quot;, stream, err, nil)<br>    }</pre><pre>    got := result.GetOutput()<br>    want := float32(30)<br>    if got != want {<br>        t.Errorf(&quot;got %v, want %v&quot;, got, want)<br>    }<br>}</pre><pre>func TestExecute(t *testing.T) {<br>    ctrl := gomock.NewController(t)<br>    defer ctrl.Finish()<br>    mockMachineClient := mock_machine.NewMockMachineClient(ctrl)</pre><pre>    mockClientStream := mock_machine.NewMockMachine_ExecuteClient(ctrl)<br>    mockClientStream.EXPECT().Send(gomock.Any()).Return(nil).AnyTimes()<br>    mockClientStream.EXPECT().Recv().Return(&amp;machine.Result{Output: 30}, nil)</pre><pre>    mockMachineClient.EXPECT().Execute(<br>        gomock.Any(), // context<br>    ).Return(mockClientStream, nil)</pre><pre>    testExecute(t, mockMachineClient)<br>}</pre><pre>           source: <a href="https://github.com/toransahu/grpc-eg-go/commit/7a5160c2b9aa6ad038d47225cd14321ef05fd019">mock_machine/machine_mock_test.go</a></pre><p>Let’s run the unit test:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go test mock_machine/machine_mock.go mock_machine/machine_mock_test.go<br>ok      command-line-arguments  0.003s</pre><h3>Run</h3><p>Now we are assured through unit tests that the business logic of the server &amp; client codes is working as expected, let’s try running the server and communicating to it via our client code.</p><h4>Server</h4><p>To spin up the server we need to run the previously created cmd/run_machine_server.go file.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go run cmd/run_machine_server.go</pre><h4>Client</h4><p>Now, let’s run the client code client/machine.go.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go run client/machine.go<br>Streaming [operator:&quot;PUSH&quot; operand:1  operator:&quot;PUSH&quot; operand:2  operator:&quot;ADD&quot;  operator:&quot;PUSH&quot; operand:3  operator:&quot;DIV&quot;  operator:&quot;PUSH&quot; operand:4  operator:&quot;MUL&quot;  operator:&quot;FIB&quot;  operator:&quot;PUSH&quot; operand:5  operator:&quot;PUSH&quot; operand:6  operator:&quot;SUB&quot; ]<br>output: 3<br>output: 1<br>output: 4<br>output: 0<br>output: 1<br>output: 1<br>output: 2<br>output: 3<br>output: -1<br>EOF</pre><h3>Bonus</h3><p>There are situations when one has to choose between <em>mocking a dependency</em> versus <em>incorporating the dependencies</em> into the test environment &amp; running them live.</p><p>The decision — whether to mock or not could be made based on:</p><ol><li>how many dependencies are there</li><li>which are the essential &amp; most used dependencies</li><li>is it feasible to install dependencies on the test (and even the developer’s) environment, etc.</li></ol><p>To one extreme we can mock everything. But the mocking effort should pay us off.</p><p>For the gRPC framework, we can run the gRPC server live &amp; write client codes to test against the business logic.<br> But spinning up a server from the test file can lead to unintended consequences that may require you to allocate a TCP port (parallel runs, multiple runs under the same CI server).</p><p>To solve this gRPC community has introduced a package called <a href="https://google.golang.org/grpc/test/bufconn">bufconn</a> under gRPC’s testing package. bufconn is a package that provides a Listener object that implements net.Conn. We can substitute this listener in a gRPC server - allowing us to spin up a server that acts as a full-fledged server that can be used for testing that talks over an in-memory buffer instead of a real port.</p><p>As bufconn already comes with the <a href="https://google.golang.org/grpc">grpc</a> go module - which we already have installed, we don&#39;t need to install it explicitly.</p><p>So, let’s create a new test file server/machine_live_test.go write the following test code to launch the gRPC server live using bufconn, and write a client to test the bidirectional RPC Execute().</p><pre>const bufSize = 1024 * 1024</pre><pre>var lis *bufconn.Listener</pre><pre>func init() {<br>    lis = bufconn.Listen(bufSize)<br>    s := grpc.NewServer()<br>    machine.RegisterMachineServer(s, &amp;MachineServer{})<br>    go func() {<br>        if err := s.Serve(lis); err != nil {<br>            log.Fatalf(&quot;Server exited with error: %v&quot;, err)<br>        }<br>    }()<br>}</pre><pre>func bufDialer(context.Context, string) (net.Conn, error) {<br>    return lis.Dial()<br>}</pre><pre>func testExecute_Live(t *testing.T, client machine.MachineClient, instructions []*machine.Instruction, wants []float32) {<br>    log.Printf(&quot;Streaming %v&quot;, instructions)<br>    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)<br>    defer cancel()<br>    stream, err := client.Execute(ctx)<br>    if err != nil {<br>        log.Fatalf(&quot;%v.Execute(ctx) = %v, %v: &quot;, client, stream, err)<br>    }<br>    waitc := make(chan struct{})<br>    go func() {<br>        i := 0<br>        for {<br>            result, err := stream.Recv()<br>            if err == io.EOF {<br>                log.Println(&quot;EOF&quot;)<br>                close(waitc)<br>                return<br>            }<br>            if err != nil {<br>                log.Printf(&quot;Err: %v&quot;, err)<br>            }<br>            log.Printf(&quot;output: %v&quot;, result.GetOutput())<br>            got := result.GetOutput()<br>            want := wants[i]<br>            if got != want {<br>                t.Errorf(&quot;got %v, want %v&quot;, got, want)<br>            }<br>            i++<br>        }<br>    }()</pre><pre>    for _, instruction := range instructions {<br>        if err := stream.Send(instruction); err != nil {<br>            log.Fatalf(&quot;%v.Send(%v) = %v: &quot;, stream, instruction, err)<br>        }<br>    }<br>    if err := stream.CloseSend(); err != nil {<br>        log.Fatalf(&quot;%v.CloseSend() got error %v, want %v&quot;, stream, err, nil)<br>    }<br>    &lt;-waitc<br>}</pre><pre>func TestExecute_Live(t *testing.T) {<br>    ctx := context.Background()<br>    conn, err := grpc.DialContext(ctx, &quot;bufnet&quot;, grpc.WithContextDialer(bufDialer), grpc.WithInsecure())<br>    if err != nil {<br>        t.Fatalf(&quot;Failed to dial bufnet: %v&quot;, err)<br>    }<br>    defer conn.Close()<br>    client := machine.NewMachineClient(conn)</pre><pre>    // try Execute()<br>    instructions := []*machine.Instruction{<br>        {Operand: 1, Operator: &quot;PUSH&quot;},<br>        {Operand: 2, Operator: &quot;PUSH&quot;},<br>        {Operator: &quot;ADD&quot;},<br>        {Operand: 3, Operator: &quot;PUSH&quot;},<br>        {Operator: &quot;DIV&quot;},<br>        {Operand: 4, Operator: &quot;PUSH&quot;},<br>        {Operator: &quot;MUL&quot;},<br>        {Operator: &quot;FIB&quot;},<br>        {Operand: 5, Operator: &quot;PUSH&quot;},<br>        {Operand: 6, Operator: &quot;PUSH&quot;},<br>        {Operator: &quot;SUB&quot;},<br>    }<br>    wants := []float32{3, 1, 4, 0, 1, 1, 2, 3, -1}<br>    testExecute_Live(t, client, instructions, wants)<br>}</pre><pre>              source: <a href="https://github.com/toransahu/grpc-eg-go/commit/95afc5b5d158252b6ff04e6b2193c30effa270ec">server/machine_live_test.go</a></pre><p>Let’s run the unit test:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go test server/machine.go server/machine_live_test.go<br>ok      command-line-arguments  0.005s</pre><p>Fantastic!!! Everything worked as expected.</p><p>At the end of this blog, we’ve learned:</p><ul><li>How to define an interface for bi-directional streaming RPC using protobuf</li><li>How to write gRPC server &amp; client logic for bi-directional streaming RPC</li><li>How to write and run the unit test for bi-directional streaming RPC</li><li>How to write and run the unit test for bi-directional streaming RPC by running the server live leveraging the bufconn package</li><li>How to run the gRPC server and a client can communicate to it</li></ul><p>The source code of this example is available at <a href="https://github.com/toransahu/grpc-eg-go">toransahu/grpc-eg-go</a>.</p><p>See you on the next blog.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c5681a61da8a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Part-2: Building a basic microservice with unidirectional-streaming gRPC using Golang]]></title>
            <link>https://toransahu.medium.com/part-2-building-a-basic-microservice-with-unidirectional-streaming-grpc-using-golang-337b580bedbe?source=rss-b49056382ee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/337b580bedbe</guid>
            <category><![CDATA[unidirectional]]></category>
            <category><![CDATA[streaming]]></category>
            <category><![CDATA[protobuf]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[grpc]]></category>
            <dc:creator><![CDATA[Toran Sahu]]></dc:creator>
            <pubDate>Thu, 25 Feb 2021 12:53:59 GMT</pubDate>
            <atom:updated>2021-02-25T13:00:10.939Z</atom:updated>
            <content:encoded><![CDATA[<p>Have you ever wondered while developing a REST API that if the server could have got the capability to stream responses using the same TCP connection? Or, reversely if the REST client could have got the capability to stream the requests to the server, this could have saved the cost of bringing up another service (like WebSocket) just for the sake of fulfilling such requirement.</p><p>Then REST isn’t the only API architecture available, and for such use-cases, the gRPC model has begun to play a crucial role. gRPC’s unidirectional-streaming RPC feature has got your back on those requirements.</p><h3>Objective</h3><p>In this blog, you’ll get to know what is client streaming &amp; server streaming uni-directional RPCs. How to implement, test, and run them using a live, fully functional example.</p><blockquote><em>Previously in the </em><a href="https://toransahu.medium.com/building-a-basic-microservice-with-grpc-using-golang-part-1-a109067178c"><em>part-1</em></a><em> of this blog series, we’ve learned the basics of gRPC, how to implement a Simple/Unary gRPC, how to write unit tests, how to launch the server &amp; client. </em><a href="https://dev.to/toransahu/part-1-building-a-basic-microservice-with-grpc-using-golang-304d"><em>part-1</em></a><em> walks you through a step-by-step guide to implement a </em>Stack Machine<em> server &amp; client leveraging Simple/Unary RPC.</em></blockquote><blockquote><em>If you’ve missed that, it is highly recommended to go through it to get familiar with the basics of the gRPC framework.</em></blockquote><h3>Introduction</h3><p>Let’s understand how Client streaming &amp; Server streaming RPCs works at a very high-level.</p><p>Client streaming RPCs where:</p><ul><li>the client writes a sequence of messages and sends them to the server using a provided stream</li><li>once the client has finished writing the messages, it waits for the server to read them and return its response</li></ul><p>Server streaming RPCs where:</p><ul><li>the client sends a request to the server and gets a stream to read a sequence of messages back</li><li>the client reads from the returned stream until there are no more messages</li></ul><p>The best thing is gRPC guarantees message ordering within an individual RPC call.</p><p>Now let’s improve the <em>“Stack Machine”</em> server &amp; client codes to support unidirectional streaming.</p><h3>Implementing Server Streaming RPC</h3><p>We’ll see an example of Server Streaming first by implementing the FIB operation.</p><p>Where the FIB RPC will:</p><ul><li>perform a Fibonacci operation</li><li>accept an integer input i.e. generate first N numbers of the Fibonacci series</li><li>will respond with a stream of integers i.e. first N numbers of the Fibonacci series</li></ul><p>And later we’ll see how Client Streaming can be implemented so that a client can input a stream of Instructions to the Stack Machine in real-time rather than sending a single request comprised of a set of Instructions.</p><h3>Update the protobuf</h3><p>We already have defined the gRPC service Machine and a Simple (Unary) RPC method Execute inside our service definition in <a href="https://dev.to/toransahu/part-1-building-a-basic-microservice-with-grpc-using-golang-304d">part-1</a> of the blog series. Now, let&#39;s update the service definition to add one server streaming RPC called ServerStreamingExecute.</p><ul><li>A server streaming RPC where the client sends a request to the server using the stub and waits for a response to come back as a stream of result</li><li>To specify a server-side streaming method, need to place the stream keyword before the response type</li></ul><pre>// ServerStreamingExecute accepts a set of Instructions from client and returns a stream of Result.<br>rpc ServerStreamingExecute(InstructionSet) returns (stream Result) {}</pre><pre>                 source: <a href="https://github.com/toransahu/grpc-eg-go/commit/689f3ec5cbd33fa1ee6ca68baa48586603b3c381">machine/machine.proto</a></pre><h3>Generating the updated client and server interface Go code</h3><p>We need to generate the gRPC client and server interfaces from our machine/machine.proto service definition.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ SRC_DIR=./<br>$ DST_DIR=$SRC_DIR<br>$ protoc \<br>  -I=$SRC_DIR \<br>  --go_out=plugins=grpc:$DST_DIR \<br>  $SRC_DIR/machine/machine.proto</pre><p>You can observe that the declaration of ServerStreamingExecute() in the MachineClient and MachineServer interface has been auto-generated:</p><pre>...</pre><pre> type MachineClient interface {<br>    Execute(ctx context.Context, in *InstructionSet, opts ...grpc.CallOption) (*Result, error)<br>+   ServerStreamingExecute(ctx context.Context, in *InstructionSet, opts ...grpc.CallOption) (Machine_ServerStreamingExecuteClient, error)<br> }</pre><pre>...</pre><pre> type MachineServer interface {<br>    Execute(context.Context, *InstructionSet) (*Result, error)<br>+   ServerStreamingExecute(*InstructionSet, Machine_ServerStreamingExecuteServer) error<br> }</pre><pre>                   source: <a href="https://github.com/toransahu/grpc-eg-go/commit/707207380c5e9b32dc30b89d5bb744d43e8335bf">machine/machine.pb.go</a></pre><h3>Update the Server</h3><p>Just in case if you’re wondering, <em>What if my service doesn’t implement some of the RPCs declared in the </em><em>machine.pb.go file</em>, then you&#39;ll encounter the following error while launching your gRPC server.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go run cmd/run_machine_server.go<br># command-line-arguments<br>cmd/run_machine_server.go:32:44: cannot use &amp;server.MachineServer literal (type *server.MachineServer) as type machine.MachineServer in argument to machine.RegisterMachineServer:<br>        *server.MachineServer does not implement machine.MachineServer (missing ServerStreamingExecute method)</pre><p>So, it’s always the best practice to keep your service in sync with the service definition i.e. machine/machine.proto &amp; machine/machine.pb.go. If you do not want to support a particular RPC, or its implementation is not yet ready, just respond with Unimplemented error status. Example:</p><pre>// ServerStreamingExecute runs the set of instructions given and streams a sequence of Results.<br>func (s *MachineServer) ServerStreamingExecute(instructions *machine.InstructionSet, stream machine.Machine_ServerStreamingExecuteServer) error {<br>    return status.Error(codes.Unimplemented, &quot;ServerStreamingExecute() not implemented yet&quot;)<br>}</pre><pre>                   source: <a href="https://github.com/toransahu/grpc-eg-go/commit/2467249a8824525439186d28374b74067d93b0e9">server/machine.go</a></pre><p>Before we implement the ServerStreamingExecute() RPC, let&#39;s write a Fibonacci series <em>generator</em> called FibonacciRange().</p><pre>package utils</pre><pre>func FibonacciRange(n int) &lt;-chan int {<br>    ch := make(chan int)<br>    fn := make([]int, n+1, n+2)<br>    fn[0] = 0<br>    fn[1] = 1<br>    go func() {<br>        defer close(ch)<br>        for i := 0; i &lt;= n; i++ {<br>            var f int<br>            if i &lt; 2 {<br>                f = fn[i]<br>            } else {<br>                f = fn[i-1] + fn[i-2]<br>            }<br>            fn[i] = f<br>            ch &lt;- f<br>        }<br>    }()<br>    return ch<br>}</pre><pre>                    source: <a href="https://github.com/toransahu/grpc-eg-go/commit/5f2a7611c8a2e8d94cb3b2a71ddee34b6f0500bf">utils/fibonacci.go</a></pre><blockquote><em>The </em><a href="https://dev.to/toransahu/series/11379"><em>blog series</em></a><em> assumes that you’re familiar with Golang basics &amp; its concurrency paradigms &amp; concepts like </em><em>Channels. You can read more about the </em><em>Channels from the </em><a href="https://tour.golang.org/concurrency/2"><em>official document</em></a><em>.</em></blockquote><p>This function yields the numbers of Fibonacci series till the Nth position.</p><p>Let’s also add a small unit test to validate the FibonacciRange() generator.</p><pre>package utils</pre><pre>import (<br>    &quot;testing&quot;<br>)</pre><pre>func TestFibonacciRange(t *testing.T) {<br>    fibOf5 := []int{0, 1, 1, 2, 3, 5}<br>    i := 0<br>    for f := range FibonacciRange(5) {<br>        if f != fibOf5[i] {<br>            t.Errorf(&quot;got %d, want %d&quot;, f, fibOf5[i])<br>        }<br>        i++<br>    }<br>}</pre><pre>                source: <a href="https://github.com/toransahu/grpc-eg-go/commit/aa80539e6c79060336a6bfc3ba1b64928e9f6cf1">utils/fibonacci_test.go</a></pre><p>Let’s implement ServerStreamingExecute() to handle the basic instructions PUSH/POP, and FIB with proper error handling. On completion of the execution of instructions set, it should POP the result from the Stack and should respond with a Result object to the client.</p><pre>func (s *MachineServer) ServerStreamingExecute(instructions *machine.InstructionSet, stream machine.Machine_ServerStreamingExecuteServer) error {<br>    if len(instructions.GetInstructions()) == 0 {<br>        return status.Error(codes.InvalidArgument, &quot;No valid instructions received&quot;)<br>    }</pre><pre>    var stack stack.Stack</pre><pre>    for _, instruction := range instructions.GetInstructions() {<br>        operand := instruction.GetOperand()<br>        operator := instruction.GetOperator()<br>        op_type := OperatorType(operator)</pre><pre>        log.Printf(&quot;Operand: %v, Operator: %v\n&quot;, operand, operator)</pre><pre>        switch op_type {<br>        case PUSH:<br>            stack.Push(float32(operand))<br>        case POP:<br>            stack.Pop()<br>        case FIB:<br>            n, popped := stack.Pop()</pre><pre>            if !popped {<br>                return status.Error(codes.Aborted, &quot;Invalid sets of instructions. Execution aborted&quot;)<br>            }</pre><pre>            if op_type == FIB {<br>                for f := range utils.FibonacciRange(int(n)) {<br>                    log.Println(float32(f))<br>                    stream.Send(&amp;machine.Result{Output: float32(f)})<br>                }<br>            }<br>        default:<br>            return status.Errorf(codes.Unimplemented, &quot;Operation &#39;%s&#39; not implemented yet&quot;, operator)<br>        }<br>    }<br>    return nil<br>}</pre><pre>                      source: <a href="https://github.com/toransahu/grpc-eg-go/commit/9d3e72a01e455599a88a57b9464d0a6fa8276721">server/machine.go</a></pre><h3>Update the Client</h3><p>Now, update the client code to call ServerStreamingExecute() where the client will be receiving numbers of the Fibonacci series through the stream and print the same.</p><pre>func runServerStreamingExecute(client machine.MachineClient, instructions *machine.InstructionSet) {<br>    log.Printf(&quot;Executing %v&quot;, instructions)<br>    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)<br>    defer cancel()<br>    stream, err := client.ServerStreamingExecute(ctx, instructions)<br>    if err != nil {<br>        log.Fatalf(&quot;%v.Execute(_) = _, %v: &quot;, client, err)<br>    }<br>    for {<br>        result, err := stream.Recv()<br>        if err == io.EOF {<br>            log.Println(&quot;EOF&quot;)<br>            break<br>        }<br>        if err != nil {<br>            log.Printf(&quot;Err: %v&quot;, err)<br>            break<br>        }<br>        log.Printf(&quot;output: %v&quot;, result.GetOutput())<br>    }<br>    log.Println(&quot;DONE!&quot;)<br>}</pre><pre>                   source: <a href="https://github.com/toransahu/grpc-eg-go/commit/f115c8dffd4e977110d63b534b62c30be5e1b4d6">client/machine.go</a></pre><h3>Test</h3><p>To write the unit test we’ll need to generate the mock of multiple interface as required.<br><a href="https://github.com/golang/mock">mockgen</a> is the ready-to-go framework for mocking in Golang, so we&#39;ll be leveraging it in our unit tests.</p><h4>Server</h4><p>As we’ve upgdated our interface i.e. machine/machine.pb.go, let&#39;s update the mock for MachineClient interface. And as we&#39;ve introduced a new RPC ServerStreamingExecute(), let&#39;s generate the mock for ServerStream interface Machine_ServerStreamingExecuteServer as well.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ mockgen github.com/toransahu/grpc-eg-go/machine MachineClient,Machine_ServerStreamingExecuteServer &gt; mock_machine/machine_mock.go</pre><p>The updated mock_machine/machine_mock.go should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/ab642a2e48ffe2263dbfd9cf054755fb7123c994">this</a>.</p><p>Now, we’re good to write unit test for server-side streaming RPC ServerStreamingExecute():</p><pre>func TestServerStreamingExecute(t *testing.T) {<br>    s := MachineServer{}</pre><pre>    // set up test table<br>    tests := []struct {<br>        instructions []*machine.Instruction<br>        want         []float32<br>    }{<br>        {<br>            instructions: []*machine.Instruction{<br>                {Operand: 5, Operator: &quot;PUSH&quot;},<br>                {Operator: &quot;FIB&quot;},<br>            },<br>            want: []float32{0, 1, 1, 2, 3, 5},<br>        },<br>        {<br>            instructions: []*machine.Instruction{<br>                {Operand: 6, Operator: &quot;PUSH&quot;},<br>                {Operator: &quot;FIB&quot;},<br>            },<br>            want: []float32{0, 1, 1, 2, 3, 5, 8},<br>        },<br>    }</pre><pre>    ctrl := gomock.NewController(t)<br>    defer ctrl.Finish()<br>    mockServerStream := mock_machine.NewMockMachine_ServerStreamingExecuteServer(ctrl)<br>    for _, tt := range tests {<br>        mockResults := []*machine.Result{}<br>        mockServerStream.EXPECT().Send(gomock.Any()).DoAndReturn(<br>            func(result *machine.Result) error {<br>                mockResults = append(mockResults, result)<br>                return nil<br>            }).AnyTimes()</pre><pre>        req := &amp;machine.InstructionSet{Instructions: tt.instructions}</pre><pre>        err := s.ServerStreamingExecute(req, mockServerStream)<br>        if err != nil {<br>            t.Errorf(&quot;ServerStreamingExecute(%v) got unexpected error: %v&quot;, req, err)<br>        }<br>        for i, result := range mockResults {<br>            got := result.GetOutput()<br>            want := tt.want[i]<br>            if got != want {<br>                t.Errorf(&quot;got %v, want %v&quot;, got, want)<br>            }<br>        }<br>    }<br>}</pre><pre>                  source: <a href="https://github.com/toransahu/grpc-eg-go/commit/bcb695bc3a6335fbc4965dceecfe74618765d5a8">server/machine_test.go</a></pre><p>Let’s run the unit test:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go test server/machine.go server/machine_test.go<br>ok      command-line-arguments  0.003s</pre><h4>Client</h4><p>For our new RPC ServerStreamingExecute(), let&#39;s add the mock for ClientStream interface Machine_ServerStreamingExecuteClient as well.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ mockgen github.com/toransahu/grpc-eg-go/machine MachineClient,Machine_ServerStreamingExecuteServer,Machine_ServerStreamingExecuteClient &gt; mock_machine/machine_mock.go</pre><pre>               source: <a href="https://github.com/toransahu/grpc-eg-go/commit/24db23a4110b241f17a4d45091f21ca389878574">mock_machine/machine_mock.go</a></pre><p>Let’s add unit test to test client-side logic for server-side streaming RPC ServerStreamingExecute() using mock MockMachine_ServerStreamingExecuteClient :</p><pre>func TestServerStreamingExecute(t *testing.T) {<br>    instructions := []*machine.Instruction{}<br>    instructions = append(instructions, &amp;machine.Instruction{Operand: 1, Operator: &quot;PUSH&quot;})<br>    instructions = append(instructions, &amp;machine.Instruction{Operator: &quot;FIB&quot;})<br>    instructionSet := &amp;machine.InstructionSet{Instructions: instructions}</pre><pre>    ctrl := gomock.NewController(t)<br>    defer ctrl.Finish()<br>    mockMachineClient := mock_machine.NewMockMachineClient(ctrl)<br>    clientStream := mock_machine.NewMockMachine_ServerStreamingExecuteClient(ctrl)</pre><pre>    clientStream.EXPECT().Recv().Return(&amp;machine.Result{Output: 0}, nil)</pre><pre>    mockMachineClient.EXPECT().ServerStreamingExecute(<br>        gomock.Any(),   // context<br>        instructionSet, // rpc uniary message<br>    ).Return(clientStream, nil)</pre><pre>    if err := testServerStreamingExecute(t, mockMachineClient, instructionSet); err != nil {<br>        t.Fatalf(&quot;Test failed: %v&quot;, err)<br>    }<br>}</pre><pre>             source: <a href="https://github.com/toransahu/grpc-eg-go/commit/b06988aa4f120a0f85ac514739603585358ead7a">mock_machine/machine_mock_test.go</a></pre><p>Let’s run the unit test:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go test mock_machine/machine_mock.go mock_machine/machine_mock_test.go<br>ok      command-line-arguments  0.003s</pre><h3>Run</h3><p>As we are assured through unit tests that the business logic of the server &amp; client codes is working as expected, let’s try running the server and communicating to it via our client code.</p><h4>Server</h4><p>To start the server we need to run the previously created cmd/run_machine_server.go file.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go run cmd/run_machine_server.go</pre><h4>Client</h4><p>Now, let’s run the client code client/machine.go.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go run client/machine.go<br>Executing instructions:&lt;operator:&quot;PUSH&quot; operand:5 &gt; instructions:&lt;operator:&quot;PUSH&quot; operand:6 &gt; instructions:&lt;operator:&quot;MUL&quot; &gt;<br>output:30<br>Executing instructions:&lt;operator:&quot;PUSH&quot; operand:6 &gt; instructions:&lt;operator:&quot;FIB&quot; &gt;<br>output: 0<br>output: 1<br>output: 1<br>output: 2<br>output: 3<br>output: 5<br>output: 8<br>EOF<br>DONE!</pre><p>Awesome! A Server Streaming RPC has been successfully implemented.</p><h3>Implementing Client Streaming RPC</h3><p>We have learned how to implement a Server Streaming RPC, now it’s time to explore the Client Streaming RPC.<br> To do so, we’ll not introduce another RPC, rather we’ll update the existing Execute() RPC to accept a stream of Instructions from the client in real-time rather than sending a single request comprised of a set of Instructions.</p><h3>Update the protobuf</h3><p>So, let’s update the interface:</p><pre>service Machine {<br>-     rpc Execute(InstructionSet) returns (Result) {}<br>+     rpc Execute(stream Instruction) returns (Result) {}<br>      rpc ServerStreamingExecute(InstructionSet) returns (stream Result) {}<br> }</pre><pre>                  source: <a href="https://github.com/toransahu/grpc-eg-go/commit/18e609afa8d7f8eb52270aa1cff8b42fd1d6728c">machine/machine.proto</a></pre><h3>Generating the updated client and server interface Go code</h3><p>Now lets generate an updated golang code from the machine/machine.proto by running:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ SRC_DIR=./<br>$ DST_DIR=$SRC_DIR<br>$ protoc \<br>  -I=$SRC_DIR \<br>  --go_out=plugins=grpc:$DST_DIR \<br>  $SRC_DIR/machine/machine.proto</pre><p>You’ll notice that declaration of Execute() has been updated from MachineServer &amp; MachineClient interfaces.</p><pre>type MachineServer interface {<br>-   Execute(context.Context, *InstructionSet) (*Result, error)<br>+   Execute(Machine_ExecuteServer) error<br>    ServerStreamingExecute(*InstructionSet, Machine_ServerStreamingExecuteServer) error<br> }</pre><pre> type MachineClient interface {<br>-    Execute(ctx context.Context, in *InstructionSet, opts ...grpc.CallOption) (*Result, error)<br>+    Execute(ctx context.Context, opts ...grpc.CallOption) (Machine_ExecuteClient, error)<br>     ServerStreamingExecute(ctx context.Context, in *InstructionSet, opts ...grpc.CallOption) (Machine_ServerStreamingExecuteClient, error)<br> }</pre><pre>                  source: <a href="https://github.com/toransahu/grpc-eg-go/commit/825bdd8a5a97af41d97a4a60dc87191e9b1e0e59">machine/machine.pb.go</a></pre><h3>Update the Server</h3><p>Let’s update the server code to make Execute() a client streaming uni-directional RPC so that it should be able to accept stream the instructions from the client and respond with a Result struct.</p><pre>func (s *MachineServer) Execute(stream machine.Machine_ExecuteServer) error {<br>    var stack stack.Stack<br>    for {<br>        instruction, err := stream.Recv()<br>        if err == io.EOF {<br>            log.Println(&quot;EOF&quot;)<br>            output, popped := stack.Pop()<br>            if !popped {<br>                return status.Error(codes.Aborted, &quot;Invalid sets of instructions. Execution aborted&quot;)<br>            }</pre><pre>            if err := stream.SendAndClose(&amp;machine.Result{<br>                Output: output,<br>            }); err != nil {<br>                return err<br>            }</pre><pre>            return nil<br>        }<br>        if err != nil {<br>            return err<br>        }</pre><pre>        operand := instruction.GetOperand()<br>        operator := instruction.GetOperator()<br>        op_type := OperatorType(operator)</pre><pre>        fmt.Printf(&quot;Operand: %v, Operator: %v\n&quot;, operand, operator)</pre><pre>        switch op_type {<br>        case PUSH:<br>            stack.Push(float32(operand))<br>        case POP:<br>            stack.Pop()<br>        case ADD, SUB, MUL, DIV:<br>            item2, popped := stack.Pop()<br>            item1, popped := stack.Pop()</pre><pre>            if !popped {<br>                return status.Error(codes.Aborted, &quot;Invalid sets of instructions. Execution aborted&quot;)<br>            }</pre><pre>            if op_type == ADD {<br>                stack.Push(item1 + item2)<br>            } else if op_type == SUB {<br>                stack.Push(item1 - item2)<br>            } else if op_type == MUL {<br>                stack.Push(item1 * item2)<br>            } else if op_type == DIV {<br>                stack.Push(item1 / item2)<br>            }</pre><pre>        default:<br>            return status.Errorf(codes.Unimplemented, &quot;Operation &#39;%s&#39; not implemented yet&quot;, operator)<br>        }<br>    }<br>}</pre><pre>                   source: <a href="https://github.com/toransahu/grpc-eg-go/commit/0136804fe1567922ae3f64796dc0e78638975109">server/machine.go</a></pre><h3>Update the Client</h3><p>Now update the client code to make client.Execute() a uni-directional streaming RPC, so that the client can stream the instructions to the server and can receive a Result struct once the streaming completes.</p><pre>func runExecute(client machine.MachineClient, instructions *machine.InstructionSet) {<br>    log.Printf(&quot;Streaming %v&quot;, instructions)<br>    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)<br>    defer cancel()<br>    stream, err := client.Execute(ctx)<br>    if err != nil {<br>        log.Fatalf(&quot;%v.Execute(ctx) = %v, %v: &quot;, client, stream, err)<br>    }<br>    for _, instruction := range instructions.GetInstructions() {<br>        if err := stream.Send(instruction); err != nil {<br>            log.Fatalf(&quot;%v.Send(%v) = %v: &quot;, stream, instruction, err)<br>        }<br>    }<br>    result, err := stream.CloseAndRecv()<br>    if err != nil {<br>        log.Fatalf(&quot;%v.CloseAndRecv() got error %v, want %v&quot;, stream, err, nil)<br>    }<br>    log.Println(result)<br>}</pre><pre>                   source: <a href="https://github.com/toransahu/grpc-eg-go/commit/91a35a9c36a69ad8005becf48bd171ca311864f4">client/machine.go</a></pre><h3>Test</h3><p>Generate mock for Machine_ExecuteClient and Machine_ExecuteServer interface to test client-streaming RPC Execute():</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ mockgen github.com/toransahu/grpc-eg-go/machine MachineClient,Machine_ServerStreamingExecuteClient,Machine_ServerStreamingExecuteServer,Machine_ExecuteServer,Machine_ExecuteClient &gt; mock_machine/machine_mock.go</pre><p>The updated mock_machine/machine_mock.go should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/6a6031df42d8a1e11346e29c6d0ff8ead898932c">this</a>.</p><h4>Server</h4><p>Let’s update the unit test to test the server-side logic of client streaming Execute() RPC using mock:</p><pre>func TestExecute(t *testing.T) {<br>    s := MachineServer{}</pre><pre>    ctrl := gomock.NewController(t)<br>    defer ctrl.Finish()<br>    mockServerStream := mock_machine.NewMockMachine_ExecuteServer(ctrl)</pre><pre>    mockResult := &amp;machine.Result{}<br>    callRecv1 := mockServerStream.EXPECT().Recv().Return(&amp;machine.Instruction{Operand: 5, Operator: &quot;PUSH&quot;}, nil)<br>    callRecv2 := mockServerStream.EXPECT().Recv().Return(&amp;machine.Instruction{Operand: 6, Operator: &quot;PUSH&quot;}, nil).After(callRecv1)<br>    callRecv3 := mockServerStream.EXPECT().Recv().Return(&amp;machine.Instruction{Operator: &quot;MUL&quot;}, nil).After(callRecv2)<br>    mockServerStream.EXPECT().Recv().Return(nil, io.EOF).After(callRecv3)<br>    mockServerStream.EXPECT().SendAndClose(gomock.Any()).DoAndReturn(<br>        func(result *machine.Result) error {<br>            mockResult = result<br>            return nil<br>        })</pre><pre>    err := s.Execute(mockServerStream)<br>    if err != nil {<br>        t.Errorf(&quot;Execute(%v) got unexpected error: %v&quot;, mockServerStream, err)<br>    }<br>    got := mockResult.GetOutput()<br>    want := float32(30)<br>    if got != want {<br>        t.Errorf(&quot;got %v, wanted %v&quot;, got, want)<br>    }<br>}</pre><pre>               source: <a href="https://github.com/toransahu/grpc-eg-go/commit/77468e91e82a6769f7edd17d0502455a6d1cd040">server/machine_test.go</a></pre><p>Let’s run the unit test:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go test server/machine.go server/machine_test.go<br>ok      command-line-arguments  0.003s</pre><h4>Client</h4><p>Now, add unit test to test client-side logic of client streaming Execute() RPC using mock:</p><pre>func TestExecute(t *testing.T) {<br>    ctrl := gomock.NewController(t)<br>    defer ctrl.Finish()<br>    mockMachineClient := mock_machine.NewMockMachineClient(ctrl)</pre><pre>    mockClientStream := mock_machine.NewMockMachine_ExecuteClient(ctrl)<br>    mockClientStream.EXPECT().Send(gomock.Any()).Return(nil).AnyTimes()<br>    mockClientStream.EXPECT().CloseAndRecv().Return(&amp;machine.Result{Output: 30}, nil)</pre><pre>    mockMachineClient.EXPECT().Execute(<br>        gomock.Any(), // context<br>    ).Return(mockClientStream, nil)</pre><pre>    testExecute(t, mockMachineClient)<br>}</pre><pre>             source: <a href="https://github.com/toransahu/grpc-eg-go/commit/40f434a4eb79fea421d58ba8eb2269c4bb3807a4">mock_machine/machine_mock_test.go</a></pre><p>Let’s run the unit test:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go test mock_machine/machine_mock.go mock_machine/machine_mock_test.go<br>ok      command-line-arguments  0.003s</pre><p>Run all the unit tests at once:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go test ./...<br>?       github.com/toransahu/grpc-eg-go/client  [no test files]<br>?       github.com/toransahu/grpc-eg-go/cmd     [no test files]<br>?       github.com/toransahu/grpc-eg-go/machine [no test files]<br>ok      github.com/toransahu/grpc-eg-go/mock_machine    (cached)<br>ok      github.com/toransahu/grpc-eg-go/server  (cached)<br>ok      github.com/toransahu/grpc-eg-go/utils   (cached)<br>?       github.com/toransahu/grpc-eg-go/utils/stack     [no test files]</pre><h3>Run</h3><p>Now we are assured through unit tests that the business logic of the server &amp; client codes is working as expected, let’s try running the server and communicating to it via our client code.</p><h4>Server</h4><p>To launch the server we need to run the previously created cmd/run_machine_server.go file.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go run cmd/run_machine_server.go</pre><h4>Client</h4><p>Now, let’s run the client code client/machine.go.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go run client/machine.go<br>Streaming instructions:&lt;operator:&quot;PUSH&quot; operand:5 &gt; instructions:&lt;operator:&quot;PUSH&quot; operand:6 &gt; instructions:&lt;operator:&quot;MUL&quot; &gt;<br>output:30<br>Executing instructions:&lt;operator:&quot;PUSH&quot; operand:6 &gt; instructions:&lt;operator:&quot;FIB&quot; &gt;<br>output: 0<br>output: 1<br>output: 1<br>output: 2<br>output: 3<br>output: 5<br>output: 8<br>EOF<br>DONE!</pre><p>Awesome!! We have successfully transformed a Unary RPC into Server Streaming RPC.</p><p>At the end of this blog, we’ve learned:</p><ul><li>How to define an interface for uni-directional streaming RPCs using protobuf</li><li>How to write gRPC server &amp; client logic for uni-directional streaming RPCs</li><li>How to write and run the unit test for server-streaming &amp; client-streaming RPCs</li><li>How to run the gRPC server and a client can communicate to it</li></ul><p>The source code of this example is available at <a href="https://github.com/toransahu/grpc-eg-go">toransahu/grpc-eg-go</a>.<br> You can also git checkout to <a href="https://github.com/toransahu/grpc-eg-go/tree/b06988aa4f120a0f85ac514739603585358ead7a">this</a> commit SHA for “Implementing Server Streaming RPC” and to <a href="https://github.com/toransahu/grpc-eg-go/tree/40f434a4eb79fea421d58ba8eb2269c4bb3807a4">this</a> commit SHA for “Implementing Client Streaming RPC”.</p><p>See you in the next part of this blog series.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=337b580bedbe" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hello All,]]></title>
            <link>https://toransahu.medium.com/hello-all-840507d23c3?source=rss-b49056382ee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/840507d23c3</guid>
            <category><![CDATA[pycon]]></category>
            <category><![CDATA[2020]]></category>
            <category><![CDATA[india]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[conference]]></category>
            <dc:creator><![CDATA[Toran Sahu]]></dc:creator>
            <pubDate>Sun, 16 Aug 2020 15:45:17 GMT</pubDate>
            <atom:updated>2020-08-16T15:59:43.401Z</atom:updated>
            <content:encoded><![CDATA[<h3>Call for PyCon India 2020</h3><p>Hello All,</p><p>This is to brief you about <a href="https://pycon.org/"><strong>PyCon</strong></a>.</p><p><strong>PyCon</strong> is the largest premier <a href="https://www.python.org/">Python</a> conference hosted all around the world, mostly organized by volunteers from local Python communities.</p><p>So thus, <a href="https://in.pycon.org/2020/"><strong>PyCon India</strong></a> is the largest gathering of Pythonistas in India for the Python programming language. Which is scheduled to be held on Oct 2nd to Oct 5th on an online platform.</p><p>This year, with the unique scenario at hand, the conference has become more accessible to make your participation right from the comfort of your homes.</p><p><strong>Schedule &amp; Venue</strong></p><p>When: Oct 2nd to Oct 5th, 2020<br> Where: Online<br> Website: <a href="https://in.pycon.org/2020/">in.pycon.org/2020</a></p><h4>Participation</h4><p>Whether you are an experienced programmer, a hobby hacker, or an absolute beginner, PyCon welcomes you to the Python community.</p><p>The conference happens in a very precise format each year. 2 days of talks on over different topics, then 2 days of hands-on which starts with a workshop followed by dev sprint.</p><p>Get your passes from <a href="https://in.pycon.org/2020/register/">here</a>.</p><h4>Volunteering</h4><p>Have you ever wished you could contribute or give back to the Python community? Well, here’s an awesome opportunity for you to do it with the year’s premier conference for the Python programming language, PyCon India 2020.</p><p>You can join any of the following groups as per your interests and skillsets and contribute.</p><ul><li>Media team</li><li>Design team</li><li>Content team</li><li>Technology team</li></ul><p>You can find various open tasks on <a href="https://github.com/pythonindia">PyCon India Github</a> account. A few topics which welcomes your contributions are:</p><ul><li>Main Website: <a href="https://github.com/pythonindia/inpycon2020/issues">pythonindia/inpycon2020</a></li><li>Blog Page: <a href="https://github.com/pythonindia/inpycon-blog/issues">pythonindia/inpycon-blog</a></li><li>Conference Management Tool: <a href="https://github.com/pythonindia/junction/issues">pythonindia/junction</a></li></ul><h4>Proposals</h4><p>The conference welcomes talks of every level. Whether you are a beginner filling the proposal for your first talk or have been giving talks for the past 10+ years. It encourages everyone to draft a proposal, no matter the difficulty level.</p><p>You can learn more about it, get the current proposal list, and also submit your proposals <a href="https://in.pycon.org/cfp/2020/proposals/">here</a>.</p><p>The best way to get the latest updates on the conference, connect with the PyCon India community, or to get answers to your queries faster, is joining the <a href="https://pyconindia.zulipchat.com.">PyCon India Zulip Channel</a>.</p><p>See you at the conference!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=840507d23c3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a basic microservice with gRPC using Golang — Part 1]]></title>
            <link>https://toransahu.medium.com/building-a-basic-microservice-with-grpc-using-golang-part-1-a109067178c?source=rss-b49056382ee6------2</link>
            <guid isPermaLink="false">https://medium.com/p/a109067178c</guid>
            <category><![CDATA[grpc]]></category>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[protobuf]]></category>
            <category><![CDATA[http2]]></category>
            <category><![CDATA[golang]]></category>
            <dc:creator><![CDATA[Toran Sahu]]></dc:creator>
            <pubDate>Sat, 04 Apr 2020 15:10:05 GMT</pubDate>
            <atom:updated>2021-02-25T11:49:09.767Z</atom:updated>
            <content:encoded><![CDATA[<h3>Part-1: Building a basic microservice with gRPC using Golang</h3><h3>Introduction</h3><p>Being easy to use, <a href="https://en.wikipedia.org/wiki/Representational_state_transfer">REST</a> <a href="https://en.wikipedia.org/wiki/Application_programming_interface">API</a> is the current most popular framework among developers for web application development. REST has been used to expose the services to the outer world, and also for internal communication among internal microservices. However, ease and flexibility come with some pitfalls. REST requires very strict <em>Human Agreement</em>, and relies on <em>Documentation</em>. Also, it has been found not so very performant in the case of internal communication and real-time applications. In 2015, <a href="https://grpc.io/">gRPC</a> kicked in. gRPC initially developed at Google is now disrupting the industry. gRPC is a modern open-source high-performance RPC framework, which comes with a simple language-agnostic <a href="https://en.wikipedia.org/wiki/Interface_description_language">Interface Definition Language</a> (IDL) system, leveraging <a href="https://developers.google.com/protocol-buffers/">Protocol Buffers</a>.</p><h3>Objective</h3><p>The purpose of this blog is to get you started with gRPC in <a href="https://golang.org/">Go</a> with a simple working example. The blog covers basic information like What, Why, When/Where, and How about the gRPC. We&#39;ll majorly focus on the How section, to implement the client and server, to write <a href="https://en.wikipedia.org/wiki/Unit_testing">unittests</a> to test the client and server code separately, and will run the code to establish a client-server communication.</p><h3>What is gRPC?</h3><p><a href="https://grpc.io/">gRPC</a> — Remote Procedure Call</p><ul><li>gRPC is a high performance, open-source universal RPC Framework</li><li>It enables the server and client applications to communicate transparently and build connected systems</li><li>gRPC is developed and open-sourced by Google (but no, the <a href="https://github.com/grpc/grpc/blob/master/doc/g_stands_for.md">g</a> doesn’t stand for Google)</li></ul><h3>Why use gRPC?</h3><p>Better Design</p><ul><li>With gRPC we can define our service once in a .proto file and implement clients and servers in any of gRPC’s supported languages</li><li>Ability to auto-generate and publish SDKs as opposed to publishing the APIs for services</li></ul><p>High Performance</p><ul><li>Advantages of working with protocol buffers, including efficient serialization, a simple <a href="https://en.wikipedia.org/wiki/Interface_description_language">IDL</a> (Interface Definition Language), and easy interface updating</li><li>Advantages of improved features of HTTP/2<br>- <em>Multiplexing</em>: This forces service-client to utilize a single TCP connection to simultaneously handle multiple requests.<br>- <em>Binary Framing and Compression</em></li></ul><p>Multi-way communication</p><ul><li>Simple/Uni-ary RPC</li><li>Server-side streaming RPC</li><li>Client-side streaming RPC</li><li>Bidirectional streaming RPC</li></ul><h3>Where to use gRPC?</h3><p>The “where” is pretty easy: we can leverage gRPC almost anywhere we have two computers communicating over a network:</p><ul><li>Microservices</li><li>Client-Server Applications</li><li>Integrations and APIs</li><li>Browser-based Web Applications</li></ul><h3>How to use gRPC?</h3><p>Our example is a simple <em>“Stack Machine”</em> as a service that lets clients perform operations like, PUSH, ADD, SUB, MUL, DIV, FIBB, AP, GP.</p><p>In Part-1 we’ll focus on Simple RPC implementation, in Part-2 we’ll focus on Server-side &amp; Client-side streaming RPC, and in Part-3 we’ll implement Bidirectional streaming RPC.</p><p>Let’s get started with installing the pre-requisites of the development.</p><h3>Prerequisites</h3><h4>Go</h4><ul><li>Version 1.6 or higher.</li><li>For installation instructions, see Go’s Getting Started guide.</li></ul><h4>gRPC</h4><p>Use the following command to install gRPC.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go get -u google.golang.org/grpc</pre><h4>Protocol Buffers v3</h4><ul><li>Install the protoc compiler that is used to generate gRPC service code. (<a href="https://developers.google.com/protocol-buffers/">https://developers.google.com/protocol-buffers/</a>)</li></ul><pre>~/disk/E/workspace/grpc-eg-go<br>$ go get -u github.com/golang/protobuf/proto</pre><ul><li>Update the environment variable PATH to include the path to the protoc binary file.</li><li>Install the protoc plugin for Go</li></ul><pre>~/disk/E/workspace/grpc-eg-go<br>$ go get -u github.com/golang/protobuf/protoc-gen-go</pre><h4>Setting Project Structure</h4><pre>~/disk/E/workspace/grpc-eg-go<br>$ go mod init github.com/toransahu/grpc-eg-go<br>$ mkdir machine<br>$ mkdir server<br>$ mkdir client</pre><pre>$ tree<br>.<br>├── client/<br>├── go.mod<br>├── machine/<br>└── server/</pre><h3>Defining the service</h3><p>Our first step is to define the gRPC service and the method request and response types using <a href="https://developers.google.com/protocol-buffers/docs/overview">protocol buffers</a>.</p><p>To define a service, we specify a named service in our machine/machine.proto file:</p><pre>service Machine {<br>   ...<br>}</pre><p>Then we define a Simple RPC method inside our service definition, specifying their request and response types.</p><ul><li>A simple RPC where the client sends a request to the server using the stub and waits for a response to come back</li></ul><pre>// Execute accepts a set of Instructions from the client and returns a Result.<br>rpc Execute(InstructionSet) returns (Result) {}</pre><ul><li>machine/machine.proto file also contains protocol buffer message type definitions for all the request and response types used in our service methods.</li></ul><pre>// Result represents the output of execution of the instruction(s).<br>message Result {<br>  float output = 1;<br>}</pre><p>Our machine/machine.proto file should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/58c3b4a7962030a9998836e879d230979a906b74">this</a> considering Part-1 of this blog series.</p><h3>Generating client and server code</h3><p>We need to generate the gRPC client and server interfaces from the machine/machine.proto service definition.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ SRC_DIR=./<br>$ DST_DIR=$SRC_DIR<br>$ protoc \<br>  -I=$SRC_DIR \<br>  --go_out=plugins=grpc:$DST_DIR \<br>  $SRC_DIR/machine/machine.proto</pre><p>Running this command generates the machine.pb.go file in the machine directory under the repository:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ tree machine/<br>.<br>├── machine/<br>│   ├── machine.pb.go<br>│   └── machine.proto</pre><h3>Server</h3><p>Let’s create the server.</p><p>There are two parts to making our Machine service do its job:</p><ul><li>Create server/machine.go: Implementing the service interface generated from our service definition; writing the business logic of our service.</li><li>Running the Machine gRPC server: Run the server to listen for requests from clients and dispatch them to the right service implementation.</li></ul><p>Have a look how our MachineServer interface should look like: <a href="https://github.com/toransahu/grpc-eg-go/commit/63604cf8cd1711d1559e5e34540b23a0e4db3cb0">grpc-eg-go/server/machine.go</a></p><pre>type MachineServer struct{}</pre><pre>// Execute runs the set of instructions given.<br>func (s *MachineServer) Execute(ctx context.Context, instructions *machine.InstructionSet) (*machine.Result, error) {<br>    return nil, status.Error(codes.Unimplemented, &quot;Execute() not implemented yet&quot;)<br>}</pre><h4>Implementing Simple RPC</h4><p>MachineServer implements only Execute() service method as of now - as per Part-1 of this blog series.<br> Execute(), just gets a InstructionSet from the client and returns the value in a Result by executing every Instruction in the InstructionSet into our <em>Stack Machine</em>.</p><p>Before implementing Execute(), let&#39;s implement a basic Stack. It should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/6951692c4fafa4e818f6680d180fd136c619ef3b">this</a>.</p><pre>type Stack []float32</pre><pre>func (s *Stack) IsEmpty() bool {<br>    return len(*s) == 0<br>}</pre><pre>func (s *Stack) Push(input float32) {<br>    *s = append(*s, input)<br>}</pre><pre>func (s *Stack) Pop() (float32, bool) {<br>    if s.IsEmpty() {<br>        return -1.0, false<br>    }<br>    item := (*s)[len(*s)-1]<br>    *s = (*s)[:len(*s)-1]<br>    return item, true<br>}</pre><p>Now, let’s implement the Execute(). It should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/77af4f0ac3a8840d6e5dcae2b8e42a575b456fe4">this</a>.</p><pre>type OperatorType string</pre><pre>const (<br>    PUSH OperatorType   = &quot;PUSH&quot;<br>    POP               = &quot;POP&quot;<br>    ADD               = &quot;ADD&quot;<br>    SUB               = &quot;SUB&quot;<br>    MUL               = &quot;MUL&quot;<br>    DIV               = &quot;DIV&quot;<br>)</pre><pre>type MachineServer struct{}</pre><pre>// Execute runs the set of instructions given.<br>func (s *MachineServer) Execute(ctx context.Context, instructions *machine.InstructionSet) (*machine.Result, error) {<br>    if len(instructions.GetInstructions()) == 0 {<br>        return nil, status.Error(codes.InvalidArgument, &quot;No valid instructions received&quot;)<br>    }</pre><pre>    var stack stack.Stack</pre><pre>    for _, instruction := range instructions.GetInstructions() {<br>        operand := instruction.GetOperand()<br>        operator := instruction.GetOperator()<br>        op_type := OperatorType(operator)</pre><pre>        fmt.Printf(&quot;Operand: %v, Operator: %v&quot;, operand, operator)</pre><pre>        switch op_type {<br>        case PUSH:<br>            stack.Push(float32(operand))<br>        case POP:<br>            stack.Pop()<br>        case ADD, SUB, MUL, DIV:<br>            item2, popped := stack.Pop()<br>            item1, popped := stack.Pop()</pre><pre>            if !popped {<br>                return &amp;machine.Result{}, status.Error(codes.Aborted, &quot;Invalide sets of instructions. Execution aborted&quot;)<br>            }</pre><pre>            if op_type == ADD {<br>                stack.Push(item1 + item2)<br>            } else if op_type == SUB {<br>                stack.Push(item1 - item2)<br>            } else if op_type == MUL {<br>                stack.Push(item1 * item2)<br>            } else if op_type == DIV {<br>                stack.Push(item1 / item2)<br>            }</pre><pre>        default:<br>            return nil, status.Errorf(codes.Unimplemented, &quot;Operation &#39;%s&#39; not implemented yet&quot;, operator)<br>        }</pre><pre>    }</pre><pre>    item, popped := stack.Pop()<br>    if !popped {<br>        return &amp;machine.Result{}, status.Error(codes.Aborted, &quot;Invalide sets of instructions. Execution aborted&quot;)<br>    }<br>    return &amp;machine.Result{Output: item}, nil<br>}</pre><p>We have implemented the Execute() to handle basic instructions like PUSH, POP, ADD, SUB, MUL, and DIV with proper error handling. On completion of the execution of the instructions set, it pops the result from Stack and returns as a Result object to the client.</p><h4>Code to run the gRPC server</h4><p>To run the gRPC server we need to:</p><ul><li>Create a new instance of the gRPC struct and make it listen to one of the TCP ports at our localhost address. As a convention default port selected for gRPC is 9111.</li><li>To serve our StackMachine service over the gRPC server, we need to register the service with the newly created gRPC server.</li></ul><p>For the development purpose, the basic insecure code to run the gRPC server should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/c39d5675ca47e7778cd410a0eb24ccd1f9dd4542">this</a>.</p><pre>var (<br>    port = flag.Int(&quot;port&quot;, 9111, &quot;Port on which gRPC server should listen TCP conn.&quot;)<br>)</pre><pre>func main() {<br>    flag.Parse()<br>    lis, err := net.Listen(&quot;tcp&quot;, fmt.Sprintf(&quot;:%d&quot;, *port))<br>    if err != nil {<br>        log.Fatalf(&quot;failed to listen: %v&quot;, err)<br>    }<br>    grpcServer := grpc.NewServer()<br>    machine.RegisterMachineServer(grpcServer, &amp;server.MachineServer{})<br>    grpcServer.Serve(lis)<br>    log.Printf(&quot;Initializing gRPC server on port %d&quot;, *port)<br>}</pre><p>We must consider strong TLS based security for our production environment. I’ll try planning to include an example of TLS implementation in this <a href="https://dev.to/toransahu/series/11379">blog series</a>.</p><h3>Client</h3><p>As we already know that the same machine/machine.proto file, which is our <a href="https://en.wikipedia.org/wiki/Interface_description_language">IDL</a> (Interface Definition Language) is capable of generating interfaces for clients as well. One has to just implement those interfaces to communicate with the gRPC server.</p><p>With having a .proto either service provider can implement an SDK, or the consumer of the service itself can implement a client in the desired programming language.</p><p>Let’s implement our version of a basic client code, which will call the Execute() method of the service. The client should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/5aa509cc8a1cffa7ffcc126fd2a30e85d350fa14">this</a>.</p><pre>var (<br>    serverAddr = flag.String(&quot;server_addr&quot;, &quot;localhost:9111&quot;, &quot;The server address in the format of host:port&quot;)<br>)</pre><pre>func runExecute(client machine.MachineClient, instructions *machine.InstructionSet) {<br>    log.Printf(&quot;Executing %v&quot;, instructions)<br>    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)<br>    defer cancel()<br>    result, err := client.Execute(ctx, instructions)<br>    if err != nil {<br>        log.Fatalf(&quot;%v.Execute(_) = _, %v: &quot;, client, err)<br>    }<br>    log.Println(result)<br>}</pre><pre>func main() {<br>    flag.Parse()<br>    var opts []grpc.DialOption<br>    opts = append(opts, grpc.WithInsecure())<br>    opts = append(opts, grpc.WithBlock())<br>    conn, err := grpc.Dial(*serverAddr, opts...)<br>    if err != nil {<br>        log.Fatalf(&quot;fail to dial: %v&quot;, err)<br>    }<br>    defer conn.Close()<br>    client := machine.NewMachineClient(conn)</pre><pre>    // try Execute()<br>    instructions := []*machine.Instruction{}<br>    instructions = append(instructions, &amp;machine.Instruction{Operand: 5, Operator: &quot;PUSH&quot;})<br>    instructions = append(instructions, &amp;machine.Instruction{Operand: 6, Operator: &quot;PUSH&quot;})<br>    instructions = append(instructions, &amp;machine.Instruction{Operator: &quot;MUL&quot;})<br>    runExecute(client, &amp;machine.InstructionSet{Instructions: instructions})<br>}</pre><h3>Test</h3><h4>Server</h4><p>Let’s write a unit test to validate our business logic of Execute() method.</p><ul><li>Create a test file server/machine_test.go</li><li>Write the unit test, it should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/eab052d4a66bdcf0a1ae7fd9111687c8ff4d5113">this</a>.</li></ul><p>Run the test file.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go test server/machine.go server/machine_test.go -v<br>=== RUN   TestExecute<br>--- PASS: TestExecute (0.00s)<br>PASS<br>ok      command-line-arguments    0.004s</pre><h4>Client</h4><p>To test client-side code without the overhead of connecting to a real server, we’ll use Mock. Mocking enables users to write light-weight unit tests to check functionalities on the client-side without invoking RPC calls to a server.</p><p>To write a unit test to validate client side business logic of calling the Execute() method:</p><ul><li>Install <a href="https://github.com/golang/mock">golang/mock</a> package</li><li>Generate mock for MachineClient</li><li>Create a test file mock/machine_mock_test.go</li><li>Write the unit test</li></ul><p>As we are leveraging the <a href="https://github.com/golang/mock">golang/mock</a> package, to install the package we need to run the following command:</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go get github.com/golang/mock/mockgen@latest</pre><p>To generate a mock of the MachineClient run the following command, the file should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/6e7dfc2cfdcd41bad1cd5a6a6e525cf94db33738">this</a>.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ mkdir mock_machine &amp;&amp; cd mock_machine<br>$ mockgen github.com/toransahu/grpc-eg-go/machine MachineClient &gt; machine_mock.go</pre><p>Write the unit test, it should look like <a href="https://github.com/toransahu/grpc-eg-go/commit/b69256d7bc6cdb41418fdb67dcf3a251072db63f">this</a>.</p><p>Run the test file.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go test mock_machine/machine_mock.go  mock_machine/machine_mock_test.go -v<br>=== RUN   TestExecute<br>output:30<br>--- PASS: TestExecute (0.00s)<br>PASS<br>ok      command-line-arguments    0.004s</pre><h3>Run</h3><p>Now we are assured through unit tests that the business logic of the server &amp; client codes is working as expected, let’s try running the server and communicating to it via our client code.</p><h4>Server</h4><p>To turn on the server we need to run the previously created cmd/run_machine_server.go file.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go run cmd/run_machine_server.go</pre><h4>Client</h4><p>Now, let’s run the client code client/machine.go.</p><pre>~/disk/E/workspace/grpc-eg-go<br>$ go run client/machine.go<br>Executing instructions:&lt;operator:&quot;PUSH&quot; operand:5 &gt; instructions:&lt;operator:&quot;PUSH&quot; operand:6 &gt; instructions:&lt;operator:&quot;MUL&quot; &gt;<br>output:30</pre><p>Hurray!!! It worked.</p><p>At the end of this blog, we’ve learned:</p><ul><li>Importance of gRPC — What, Why, Where</li><li>How to install all the prerequisites</li><li>How to define an interface using protobuf</li><li>How to write gRPC server &amp; client logic for Simple RPC</li><li>How to write and run the unit test for server &amp; client logic</li><li>How to run the gRPC server and a client can communicate to it</li></ul><p>The source code of this example is available at <a href="https://github.com/toransahu/grpc-eg-go">toransahu/grpc-eg-go</a>.<br> You can also git checkout to <a href="https://github.com/toransahu/grpc-eg-go/tree/14cca388a9e0a2a3c44b8e41b94f4172710d2422">this</a> commit SHA to walk through the source code specific to this Part-1 of the blog series.</p><p>See you in the next part of this <a href="https://dev.to/toransahu/series/11379">blog series</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a109067178c" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>