Files
inp2p/internal/server/server_test.go
openclaw 91e3d4da2a feat: INP2P v0.1.0 — complete P2P tunneling system
Core modules (M1-M6):
- pkg/protocol: message format, encoding, NAT type enums
- pkg/config: server/client config structs, env vars, validation
- pkg/auth: CRC64 token, TOTP gen/verify, one-time relay tokens
- pkg/nat: UDP/TCP STUN client and server
- pkg/signal: WSS message dispatch, sync request/response
- pkg/punch: UDP/TCP hole punching + priority chain
- pkg/mux: stream multiplexer (7B frame: StreamID+Flags+Len)
- pkg/tunnel: mux-based port forwarding with stats
- pkg/relay: relay manager with TOTP auth + session bridging
- internal/server: signaling server (login/heartbeat/report/coordinator)
- internal/client: client (NAT detect/login/punch/relay/reconnect)
- cmd/inp2ps + cmd/inp2pc: main entrypoints with graceful shutdown

All tests pass: 16 tests across 5 packages
Code: 3559 lines core + 861 lines tests = 19 source files
2026-03-02 15:13:22 +08:00

152 lines
3.7 KiB
Go

package server
import (
"fmt"
"log"
"net/http"
"testing"
"time"
"github.com/openp2p-cn/inp2p/pkg/config"
"github.com/openp2p-cn/inp2p/pkg/nat"
"github.com/openp2p-cn/inp2p/pkg/protocol"
"github.com/openp2p-cn/inp2p/pkg/signal"
"github.com/gorilla/websocket"
)
func TestLoginFlow(t *testing.T) {
// Start server
cfg := config.DefaultServerConfig()
cfg.WSPort = 29300
cfg.Token = 999
srv := New(cfg)
mux := http.NewServeMux()
mux.HandleFunc("/ws", srv.HandleWS)
go http.ListenAndServe(fmt.Sprintf(":%d", cfg.WSPort), mux)
time.Sleep(200 * time.Millisecond)
// Connect as client manually
ws, _, err := websocket.DefaultDialer.Dial(fmt.Sprintf("ws://127.0.0.1:%d/ws", cfg.WSPort), nil)
if err != nil {
t.Fatal(err)
}
conn := signal.NewConn(ws)
defer conn.Close()
// Start read loop in background
go conn.ReadLoop()
// Send login
loginReq := protocol.LoginReq{
Node: "testNode",
Token: 999,
Version: "test",
NATType: protocol.NATCone,
}
rspData, err := conn.Request(
protocol.MsgLogin, protocol.SubLoginReq, loginReq,
protocol.MsgLogin, protocol.SubLoginRsp,
5*time.Second,
)
if err != nil {
t.Fatalf("login request failed: %v", err)
}
var rsp protocol.LoginRsp
protocol.DecodePayload(rspData, &rsp)
if rsp.Error != 0 {
t.Fatalf("login error: %d %s", rsp.Error, rsp.Detail)
}
log.Printf("Login OK: node=%s", rsp.Node)
// Verify node is registered
time.Sleep(100 * time.Millisecond)
nodes := srv.GetOnlineNodes()
if len(nodes) != 1 {
t.Fatalf("expected 1 node, got %d", len(nodes))
}
if nodes[0].Name != "testNode" {
t.Fatalf("expected testNode, got %s", nodes[0].Name)
}
srv.Stop()
}
func TestTwoClientsWithSTUN(t *testing.T) {
cfg := config.DefaultServerConfig()
cfg.WSPort = 29301
cfg.STUNUDP1 = 29382
cfg.STUNUDP2 = 29384
cfg.STUNTCP1 = 29380
cfg.STUNTCP2 = 29381
cfg.Token = 888
// STUN
stunQuit := make(chan struct{})
defer close(stunQuit)
go nat.ServeUDPSTUN(cfg.STUNUDP1, stunQuit)
go nat.ServeUDPSTUN(cfg.STUNUDP2, stunQuit)
go nat.ServeTCPSTUN(cfg.STUNTCP1, stunQuit)
go nat.ServeTCPSTUN(cfg.STUNTCP2, stunQuit)
srv := New(cfg)
srv.StartCleanup()
mux := http.NewServeMux()
mux.HandleFunc("/ws", srv.HandleWS)
go http.ListenAndServe(fmt.Sprintf(":%d", cfg.WSPort), mux)
time.Sleep(300 * time.Millisecond)
// NAT detect
natResult := nat.Detect("127.0.0.1", cfg.STUNUDP1, cfg.STUNUDP2, cfg.STUNTCP1, cfg.STUNTCP2)
log.Printf("NAT: type=%s publicIP=%s", natResult.Type, natResult.PublicIP)
// Client A
connectClient := func(name string, relay bool) *signal.Conn {
ws, _, err := websocket.DefaultDialer.Dial(fmt.Sprintf("ws://127.0.0.1:%d/ws", cfg.WSPort), nil)
if err != nil {
t.Fatalf("dial %s: %v", name, err)
}
conn := signal.NewConn(ws)
go conn.ReadLoop()
rspData, err := conn.Request(
protocol.MsgLogin, protocol.SubLoginReq,
protocol.LoginReq{Node: name, Token: 888, Version: "test", NATType: natResult.Type, RelayEnabled: relay},
protocol.MsgLogin, protocol.SubLoginRsp,
5*time.Second,
)
if err != nil {
t.Fatalf("login %s: %v", name, err)
}
var rsp protocol.LoginRsp
protocol.DecodePayload(rspData, &rsp)
if rsp.Error != 0 {
t.Fatalf("login %s error: %s", name, rsp.Detail)
}
log.Printf("%s login ok", name)
return conn
}
connA := connectClient("nodeA", true)
defer connA.Close()
connB := connectClient("nodeB", false)
defer connB.Close()
time.Sleep(200 * time.Millisecond)
nodes := srv.GetOnlineNodes()
if len(nodes) != 2 {
t.Fatalf("expected 2 nodes, got %d", len(nodes))
}
// Test relay node discovery
relays := srv.GetRelayNodes("", "nodeB")
if len(relays) != 1 || relays[0].Name != "nodeA" {
t.Fatalf("expected nodeA as relay, got %v", relays)
}
log.Printf("Relay nodes: %v", relays[0].Name)
srv.Stop()
}