github.com/ethereum/go-ethereum@v1.16.1/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  	"bufio"
    21  	"bytes"
    22  	"io"
    23  	"net"
    24  	"os"
    25  	"path/filepath"
    26  	"strings"
    27  	"testing"
    28  	"time"
    29  )
    30  
    31  func TestServerRegisterName(t *testing.T) {
    32  	t.Parallel()
    33  
    34  	server := NewServer()
    35  	service := new(testService)
    36  
    37  	svcName := "test"
    38  	if err := server.RegisterName(svcName, service); err != nil {
    39  		t.Fatalf("%v", err)
    40  	}
    41  
    42  	if len(server.services.services) != 2 {
    43  		t.Fatalf("Expected 2 service entries, got %d", len(server.services.services))
    44  	}
    45  
    46  	svc, ok := server.services.services[svcName]
    47  	if !ok {
    48  		t.Fatalf("Expected service %s to be registered", svcName)
    49  	}
    50  
    51  	wantCallbacks := 14
    52  	if len(svc.callbacks) != wantCallbacks {
    53  		t.Errorf("Expected %d callbacks for service 'service', got %d", wantCallbacks, len(svc.callbacks))
    54  	}
    55  }
    56  
    57  func TestServer(t *testing.T) {
    58  	t.Parallel()
    59  
    60  	files, err := os.ReadDir("testdata")
    61  	if err != nil {
    62  		t.Fatal("where'd my testdata go?")
    63  	}
    64  	for _, f := range files {
    65  		if f.IsDir() || strings.HasPrefix(f.Name(), ".") {
    66  			continue
    67  		}
    68  		path := filepath.Join("testdata", f.Name())
    69  		name := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))
    70  		t.Run(name, func(t *testing.T) {
    71  			t.Parallel()
    72  
    73  			runTestScript(t, path)
    74  		})
    75  	}
    76  }
    77  
    78  func runTestScript(t *testing.T, file string) {
    79  	server := newTestServer()
    80  	server.SetBatchLimits(4, 100000)
    81  	content, err := os.ReadFile(file)
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  
    86  	clientConn, serverConn := net.Pipe()
    87  	defer clientConn.Close()
    88  	go server.ServeCodec(NewCodec(serverConn), 0)
    89  	readbuf := bufio.NewReader(clientConn)
    90  	for _, line := range strings.Split(string(content), "\n") {
    91  		line = strings.TrimSpace(line)
    92  		switch {
    93  		case len(line) == 0 || strings.HasPrefix(line, "//"):
    94  			// skip comments, blank lines
    95  			continue
    96  		case strings.HasPrefix(line, "--> "):
    97  			t.Log(line)
    98  			// write to connection
    99  			clientConn.SetWriteDeadline(time.Now().Add(5 * time.Second))
   100  			if _, err := io.WriteString(clientConn, line[4:]+"\n"); err != nil {
   101  				t.Fatalf("write error: %v", err)
   102  			}
   103  		case strings.HasPrefix(line, "<-- "):
   104  			t.Log(line)
   105  			want := line[4:]
   106  			// read line from connection and compare text
   107  			clientConn.SetReadDeadline(time.Now().Add(5 * time.Second))
   108  			sent, err := readbuf.ReadString('\n')
   109  			if err != nil {
   110  				t.Fatalf("read error: %v", err)
   111  			}
   112  			sent = strings.TrimRight(sent, "\r\n")
   113  			if sent != want {
   114  				t.Errorf("wrong line from server\ngot:  %s\nwant: %s", sent, want)
   115  			}
   116  		default:
   117  			panic("invalid line in test script: " + line)
   118  		}
   119  	}
   120  }
   121  
   122  // This test checks that responses are delivered for very short-lived connections that
   123  // only carry a single request.
   124  func TestServerShortLivedConn(t *testing.T) {
   125  	t.Parallel()
   126  
   127  	server := newTestServer()
   128  	defer server.Stop()
   129  
   130  	listener, err := net.Listen("tcp", "127.0.0.1:0")
   131  	if err != nil {
   132  		t.Fatal("can't listen:", err)
   133  	}
   134  	defer listener.Close()
   135  	go server.ServeListener(listener)
   136  
   137  	var (
   138  		request  = `{"jsonrpc":"2.0","id":1,"method":"rpc_modules"}` + "\n"
   139  		wantResp = `{"jsonrpc":"2.0","id":1,"result":{"nftest":"1.0","rpc":"1.0","test":"1.0"}}` + "\n"
   140  		deadline = time.Now().Add(10 * time.Second)
   141  	)
   142  	for i := 0; i < 20; i++ {
   143  		conn, err := net.Dial("tcp", listener.Addr().String())
   144  		if err != nil {
   145  			t.Fatal("can't dial:", err)
   146  		}
   147  
   148  		conn.SetDeadline(deadline)
   149  		// Write the request, then half-close the connection so the server stops reading.
   150  		conn.Write([]byte(request))
   151  		conn.(*net.TCPConn).CloseWrite()
   152  		// Now try to get the response.
   153  		buf := make([]byte, 2000)
   154  		n, err := conn.Read(buf)
   155  		conn.Close()
   156  
   157  		if err != nil {
   158  			t.Fatal("read error:", err)
   159  		}
   160  		if !bytes.Equal(buf[:n], []byte(wantResp)) {
   161  			t.Fatalf("wrong response: %s", buf[:n])
   162  		}
   163  	}
   164  }
   165  
   166  func TestServerBatchResponseSizeLimit(t *testing.T) {
   167  	t.Parallel()
   168  
   169  	server := newTestServer()
   170  	defer server.Stop()
   171  	server.SetBatchLimits(100, 60)
   172  	var (
   173  		batch  []BatchElem
   174  		client = DialInProc(server)
   175  	)
   176  	for i := 0; i < 5; i++ {
   177  		batch = append(batch, BatchElem{
   178  			Method: "test_echo",
   179  			Args:   []any{"x", 1},
   180  			Result: new(echoResult),
   181  		})
   182  	}
   183  	if err := client.BatchCall(batch); err != nil {
   184  		t.Fatal("error sending batch:", err)
   185  	}
   186  	for i := range batch {
   187  		// We expect the first two queries to be ok, but after that the size limit takes effect.
   188  		if i < 2 {
   189  			if batch[i].Error != nil {
   190  				t.Fatalf("batch elem %d has unexpected error: %v", i, batch[i].Error)
   191  			}
   192  			continue
   193  		}
   194  		// After two, we expect an error.
   195  		re, ok := batch[i].Error.(Error)
   196  		if !ok {
   197  			t.Fatalf("batch elem %d has wrong error: %v", i, batch[i].Error)
   198  		}
   199  		wantedCode := errcodeResponseTooLarge
   200  		if re.ErrorCode() != wantedCode {
   201  			t.Errorf("batch elem %d wrong error code, have %d want %d", i, re.ErrorCode(), wantedCode)
   202  		}
   203  	}
   204  }