github.com/klaytn/klaytn@v1.12.1/networks/rpc/server_test.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package rpc
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"net"
    24  	"testing"
    25  	"time"
    26  )
    27  
    28  type Service struct{}
    29  
    30  type Args struct {
    31  	S string
    32  }
    33  
    34  func (s *Service) NoArgsRets() {
    35  }
    36  
    37  type Result struct {
    38  	String string
    39  	Int    int
    40  	Args   *Args
    41  }
    42  
    43  func (s *Service) Echo(str string, i int, args *Args) Result {
    44  	return Result{str, i, args}
    45  }
    46  
    47  func (s *Service) EchoWithCtx(ctx context.Context, str string, i int, args *Args) Result {
    48  	return Result{str, i, args}
    49  }
    50  
    51  func (s *Service) Sleep(ctx context.Context, duration time.Duration) {
    52  	select {
    53  	case <-time.After(duration):
    54  	case <-ctx.Done():
    55  	}
    56  }
    57  
    58  func (s *Service) Rets() (string, error) {
    59  	return "", nil
    60  }
    61  
    62  func (s *Service) InvalidRets1() (error, string) {
    63  	return nil, ""
    64  }
    65  
    66  func (s *Service) InvalidRets2() (string, string) {
    67  	return "", ""
    68  }
    69  
    70  func (s *Service) InvalidRets3() (string, string, error) {
    71  	return "", "", nil
    72  }
    73  
    74  func (s *Service) Subscription(ctx context.Context) (*Subscription, error) {
    75  	return nil, nil
    76  }
    77  
    78  func TestServerRegisterName(t *testing.T) {
    79  	server := NewServer()
    80  	service := new(Service)
    81  
    82  	if err := server.RegisterName("calc", service); err != nil {
    83  		t.Fatalf("%v", err)
    84  	}
    85  
    86  	if len(server.services.services) != 2 {
    87  		t.Fatalf("Expected 2 service entries, got %d", len(server.services.services))
    88  	}
    89  
    90  	svc, ok := server.services.services["calc"]
    91  	if !ok {
    92  		t.Fatalf("Expected service calc to be registered")
    93  	}
    94  
    95  	if len(svc.callbacks) != 5 {
    96  		t.Errorf("Expected 5 callbacks for service 'calc', got %d", len(svc.callbacks))
    97  	}
    98  
    99  	if len(svc.subscriptions) != 1 {
   100  		t.Errorf("Expected 1 subscription for service 'calc', got %d", len(svc.subscriptions))
   101  	}
   102  }
   103  
   104  func testServerMethodExecution(t *testing.T, method string) {
   105  	server := NewServer()
   106  	service := new(Service)
   107  
   108  	if err := server.RegisterName("test", service); err != nil {
   109  		t.Fatalf("%v", err)
   110  	}
   111  
   112  	stringArg := "string arg"
   113  	intArg := 1122
   114  	argsArg := &Args{"abcde"}
   115  	params := []interface{}{stringArg, intArg, argsArg}
   116  
   117  	request := map[string]interface{}{
   118  		"id":      12345,
   119  		"method":  "test_" + method,
   120  		"version": "2.0",
   121  		"params":  params,
   122  	}
   123  
   124  	clientConn, serverConn := net.Pipe()
   125  	defer clientConn.Close()
   126  
   127  	go server.ServeCodec(NewCodec(serverConn), 0)
   128  
   129  	out := json.NewEncoder(clientConn)
   130  	in := json.NewDecoder(clientConn)
   131  
   132  	if err := out.Encode(request); err != nil {
   133  		t.Fatal(err)
   134  	}
   135  
   136  	var msg jsonrpcMessage
   137  	if err := in.Decode(&msg); err != nil {
   138  		t.Fatal(err)
   139  	}
   140  
   141  	if !msg.isResponse() {
   142  		t.Fatal("message is not response")
   143  	}
   144  }
   145  
   146  func TestServerMethodExecution(t *testing.T) {
   147  	testServerMethodExecution(t, "echo")
   148  }
   149  
   150  func TestServerMethodWithCtx(t *testing.T) {
   151  	testServerMethodExecution(t, "echoWithCtx")
   152  }
   153  
   154  // This test checks that responses are delivered for very short-lived connections that
   155  // only carry a single request.
   156  func TestServerShortLivedConn(t *testing.T) {
   157  	server := newTestServer("service", new(Service))
   158  	defer server.Stop()
   159  
   160  	listener, err := net.Listen("tcp", "127.0.0.1:0")
   161  	if err != nil {
   162  		t.Fatal("can't listen:", err)
   163  	}
   164  	defer listener.Close()
   165  	go server.ServeListener(listener)
   166  
   167  	var (
   168  		request  = `{"jsonrpc":"2.0","id":1,"method":"rpc_modules"}` + "\n"
   169  		wantResp = `{"jsonrpc":"2.0","id":1,"result":{"rpc":"1.0","service":"1.0"}}` + "\n"
   170  		deadline = time.Now().Add(10 * time.Second)
   171  	)
   172  	for i := 0; i < 20; i++ {
   173  		conn, err := net.Dial("tcp", listener.Addr().String())
   174  		if err != nil {
   175  			t.Fatal("can't dial:", err)
   176  		}
   177  		defer conn.Close()
   178  		conn.SetDeadline(deadline)
   179  		// Write the request, then half-close the connection so the server stops reading.
   180  		conn.Write([]byte(request))
   181  		conn.(*net.TCPConn).CloseWrite()
   182  		// Now try to get the response.
   183  		buf := make([]byte, 2000)
   184  		n, err := conn.Read(buf)
   185  		if err != nil {
   186  			t.Fatal("read error:", err)
   187  		}
   188  		if !bytes.Equal(buf[:n], []byte(wantResp)) {
   189  			t.Fatalf("wrong response: %s", buf[:n])
   190  		}
   191  	}
   192  }