176 lines
4.4 KiB
Go
176 lines
4.4 KiB
Go
package wire
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"go.uber.org/zap/zaptest"
|
|
"google.golang.org/protobuf/proto"
|
|
"nhooyr.io/websocket"
|
|
|
|
iop "iop/proto/gen/iop"
|
|
proto_socket "git.toki-labs.com/toki/proto-socket/go"
|
|
)
|
|
|
|
func getFreePort(t *testing.T) int {
|
|
t.Helper()
|
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatalf("failed to find free port: %v", err)
|
|
}
|
|
defer ln.Close()
|
|
return ln.Addr().(*net.TCPAddr).Port
|
|
}
|
|
|
|
func TestPortalServerHandshake(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
port := getFreePort(t)
|
|
listenAddr := fmt.Sprintf("127.0.0.1:%d", port)
|
|
|
|
server, err := NewPortalServer(listenAddr, logger)
|
|
if err != nil {
|
|
t.Fatalf("NewPortalServer failed: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
if err := server.Start(ctx); err != nil {
|
|
t.Fatalf("server Start failed: %v", err)
|
|
}
|
|
defer func() {
|
|
_ = server.Stop()
|
|
}()
|
|
|
|
// Give a tiny moment for server to bind
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
// Dial to the portal endpoint
|
|
parserMap := proto_socket.ParserMap{
|
|
proto_socket.TypeNameOf(&iop.PortalHelloRequest{}): func(b []byte) (proto.Message, error) {
|
|
req := &iop.PortalHelloRequest{}
|
|
return req, proto.Unmarshal(b, req)
|
|
},
|
|
proto_socket.TypeNameOf(&iop.PortalHelloResponse{}): func(b []byte) (proto.Message, error) {
|
|
res := &iop.PortalHelloResponse{}
|
|
return res, proto.Unmarshal(b, res)
|
|
},
|
|
}
|
|
|
|
// Dial using WS client
|
|
client, err := proto_socket.DialWsWithHeartbeat(
|
|
ctx,
|
|
"127.0.0.1",
|
|
port,
|
|
"/portal",
|
|
proto_socket.DefaultHeartbeatIntervalSec,
|
|
proto_socket.DefaultHeartbeatWaitSec,
|
|
parserMap,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("failed to DialWs: %v", err)
|
|
}
|
|
defer client.Close()
|
|
|
|
// Send PortalHelloRequest and wait for PortalHelloResponse
|
|
req := &iop.PortalHelloRequest{
|
|
ClientId: "test-client-id",
|
|
ClientVersion: "1.0.0",
|
|
}
|
|
|
|
res, err := proto_socket.SendRequestTyped[*iop.PortalHelloRequest, *iop.PortalHelloResponse](
|
|
&client.Communicator,
|
|
req,
|
|
2*time.Second,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("SendRequestTyped failed: %v", err)
|
|
}
|
|
|
|
if !res.Ready {
|
|
t.Errorf("expected response.Ready to be true, got false")
|
|
}
|
|
if res.Protocol != Protocol {
|
|
t.Errorf("expected response.Protocol to be %q, got %q", Protocol, res.Protocol)
|
|
}
|
|
if res.ServerTimeUnixNano <= 0 {
|
|
t.Errorf("expected server time unix nano to be positive, got %d", res.ServerTimeUnixNano)
|
|
}
|
|
if res.Message != "Hello from IOP Control Plane" {
|
|
t.Errorf("expected message to be %q, got %q", "Hello from IOP Control Plane", res.Message)
|
|
}
|
|
}
|
|
|
|
func TestPortalServerHandshakeWithBrowserOrigin(t *testing.T) {
|
|
logger := zaptest.NewLogger(t)
|
|
port := getFreePort(t)
|
|
listenAddr := fmt.Sprintf("127.0.0.1:%d", port)
|
|
|
|
server, err := NewPortalServer(listenAddr, logger)
|
|
if err != nil {
|
|
t.Fatalf("NewPortalServer failed: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
if err := server.Start(ctx); err != nil {
|
|
t.Fatalf("server Start failed: %v", err)
|
|
}
|
|
defer func() {
|
|
_ = server.Stop()
|
|
}()
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
parserMap := proto_socket.ParserMap{
|
|
proto_socket.TypeNameOf(&iop.PortalHelloRequest{}): func(b []byte) (proto.Message, error) {
|
|
req := &iop.PortalHelloRequest{}
|
|
return req, proto.Unmarshal(b, req)
|
|
},
|
|
proto_socket.TypeNameOf(&iop.PortalHelloResponse{}): func(b []byte) (proto.Message, error) {
|
|
res := &iop.PortalHelloResponse{}
|
|
return res, proto.Unmarshal(b, res)
|
|
},
|
|
}
|
|
|
|
// Dial specifying browser Origin
|
|
dialOpts := &websocket.DialOptions{
|
|
HTTPHeader: map[string][]string{
|
|
"Origin": {"http://localhost:3000"},
|
|
},
|
|
}
|
|
conn, _, err := websocket.Dial(ctx, fmt.Sprintf("ws://127.0.0.1:%d/portal", port), dialOpts)
|
|
if err != nil {
|
|
t.Fatalf("failed to Dial with Origin: %v", err)
|
|
}
|
|
|
|
// Wrap in WsClient
|
|
client := proto_socket.NewWsClient(conn, proto_socket.DefaultHeartbeatIntervalSec, proto_socket.DefaultHeartbeatWaitSec, parserMap)
|
|
defer client.Close()
|
|
|
|
// Send PortalHelloRequest
|
|
req := &iop.PortalHelloRequest{
|
|
ClientId: "browser-client",
|
|
ClientVersion: "1.0.0",
|
|
}
|
|
|
|
res, err := proto_socket.SendRequestTyped[*iop.PortalHelloRequest, *iop.PortalHelloResponse](
|
|
&client.Communicator,
|
|
req,
|
|
2*time.Second,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("SendRequestTyped failed: %v", err)
|
|
}
|
|
|
|
if !res.Ready {
|
|
t.Errorf("expected response.Ready to be true, got false")
|
|
}
|
|
if res.Protocol != Protocol {
|
|
t.Errorf("expected response.Protocol to be %q, got %q", Protocol, res.Protocol)
|
|
}
|
|
}
|