decred.org/dcrdex@v1.0.5/server/noderelay/noderelay_test.go (about)

     1  //go:build live
     2  
     3  package noderelay
     4  
     5  import (
     6  	"context"
     7  	"encoding/json"
     8  	"fmt"
     9  	"io"
    10  	"net"
    11  	"net/http"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	"decred.org/dcrdex/client/comms"
    19  	"decred.org/dcrdex/dex"
    20  )
    21  
    22  func TestNexus(t *testing.T) {
    23  	netAddr, _ := net.ResolveTCPAddr("tcp", "localhost:0")
    24  	l, _ := net.ListenTCP("tcp", netAddr)
    25  	addr := l.Addr().String()
    26  	l.Close()
    27  	_, port, err := net.SplitHostPort(addr)
    28  	if err != nil {
    29  		t.Fatalf("error splitting host and port from address %q", addr)
    30  	}
    31  
    32  	dir, err := os.MkdirTemp("", "")
    33  	if err != nil {
    34  		t.Fatalf("Error making temp dir: %v", err)
    35  	}
    36  	defer os.RemoveAll(dir)
    37  
    38  	relayID := "0xabcanything_you-want"
    39  
    40  	cfg := &NexusConfig{
    41  		Port:     port,
    42  		Dir:      dir,
    43  		Key:      filepath.Join(dir, "t.key"),
    44  		Cert:     filepath.Join(dir, "t.cert"),
    45  		Logger:   dex.StdOutLogger("T", dex.LevelDebug),
    46  		RelayIDs: []string{relayID},
    47  	}
    48  
    49  	n, err := NewNexus(cfg)
    50  	if err != nil {
    51  		t.Fatalf("NewNexus error: %v", err)
    52  	}
    53  
    54  	certB, err := os.ReadFile(cfg.Cert)
    55  	if err != nil {
    56  		t.Fatalf("Error reading certificate file: %v", err)
    57  	}
    58  
    59  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    60  	defer cancel()
    61  	if _, err = n.Connect(ctx); err != nil {
    62  		t.Fatalf("Start error: %v", err)
    63  	}
    64  
    65  	time.Sleep(2 * time.Second)
    66  
    67  	relayAddr, err := n.RelayAddr(relayID)
    68  	if err != nil {
    69  		t.Fatalf("RelayAddr error: %v", err)
    70  	}
    71  
    72  	firstRequest, firstResponse := "firstRequest", "firstResponse"
    73  	var rawHandlerErr error
    74  
    75  	var cl comms.WsConn
    76  	cl, err = comms.NewWsConn(&comms.WsCfg{
    77  		URL:      "wss://" + addr,
    78  		PingWait: 20 * time.Second,
    79  		Cert:     certB,
    80  		ReconnectSync: func() {
    81  			cancel()
    82  		},
    83  		ConnectEventFunc: func(s comms.ConnectionStatus) {},
    84  		Logger:           dex.StdOutLogger("CL", dex.LevelDebug),
    85  		RawHandler: func(b []byte) {
    86  			var req *RelayedMessage
    87  			if err := json.Unmarshal(b, &req); err != nil {
    88  				t.Fatalf("Error unmarshaling raw message: %v", err)
    89  			}
    90  			switch req.MessageID {
    91  			case 1:
    92  				if string(req.Body) != firstRequest {
    93  					rawHandlerErr = fmt.Errorf("first request had unexpected body %s != %s", string(req.Body), firstRequest)
    94  					cancel()
    95  					return
    96  				}
    97  				msgB, _ := json.Marshal(&RelayedMessage{
    98  					MessageID: 1,
    99  					Body:      []byte(firstResponse),
   100  				})
   101  				if err := cl.SendRaw(msgB); err != nil {
   102  					rawHandlerErr = fmt.Errorf("Send error: %w", err)
   103  					cancel()
   104  				}
   105  			}
   106  		},
   107  	})
   108  	if err != nil {
   109  		t.Fatalf("NewWsConn error: %v", err)
   110  	}
   111  
   112  	cm := dex.NewConnectionMaster(cl)
   113  	if err := cm.ConnectOnce(ctx); err != nil {
   114  		t.Fatalf("ConnectOnce error: %v", err)
   115  	}
   116  
   117  	msgB, _ := json.Marshal(&RelayedMessage{
   118  		MessageID: 0, // 0 is always the node ID
   119  		Body:      []byte(relayID),
   120  	})
   121  
   122  	cl.SendRaw(msgB)
   123  
   124  	select {
   125  	case <-n.WaitForSourceNodes():
   126  	case <-ctx.Done():
   127  		return
   128  	case <-time.After(time.Second * 5):
   129  		t.Fatal("timed out waiting for source nodes to connect")
   130  	}
   131  
   132  	// Now act like an asset backend and send a request through the relay node.
   133  	relayURL := "http://" + relayAddr
   134  	resp, err := http.DefaultClient.Post(relayURL, "application/json", strings.NewReader(firstRequest))
   135  	if err != nil {
   136  		t.Fatalf("Post error: %v", err)
   137  	}
   138  
   139  	b, err := io.ReadAll(resp.Body)
   140  	resp.Body.Close()
   141  	if err != nil {
   142  		t.Fatalf("First response read error: %v", err)
   143  	}
   144  	respBody := strings.TrimSpace(string(b))
   145  	if respBody != firstResponse {
   146  		t.Fatalf("wrong first response. %s != %s", string(b), firstResponse)
   147  	}
   148  	cancel()
   149  	cm.Wait()
   150  	n.wg.Wait()
   151  
   152  	if rawHandlerErr != nil {
   153  		t.Fatalf("Error generated in node source request handling: %v", rawHandlerErr)
   154  	}
   155  	fmt.Println("!!!!! Success !!!!!")
   156  }